KAEDE Hack blog

JavaScript 中心に ライブラリなどの使い方を解説する技術ブログ。

React-Router-SPA-Netlify

Reactは最終的にbundle.jsに全てを襲爵するSingle Page App, SPAである

しかしRouteを使うことによってRequestが来た時に擬似的に複数ページを ユーザーに見せることができる.やってみる

why

職場のコーポレートサイト制作での複数ページ導入に.

code

$ npm install -S react-router-dom

www.djamware.com

参考にしてindex.jsで

import { BrowserRouter as Router, Route, Switch, } from 'react-router-dom';
import App from './App';
import Works from './components/Works';
.........
ReactDOM.render(
  <Router>
      <div>
        <Route exact path='/' component={App} />
        <Route path='/works' component={Works} />
      </div>
  </Router>,
  document.getElementById('root')
);

を埋め込む

そしてWorksを作成し,一部書き換え

<Col className='py-3 bg-secondary'           
  xs={9} >                                   
  電球,蛍光灯,電池交換,テレビ,エアコン, 
</Col>                                       

urlで /works/にアクセスすると表示された!

f:id:kei_s_lifehack:20200514152050p:plain

しかしdeployしたnetlifyではダメだった

tried

とりあえずマッチしなければAppに返すようにSwitchで挟む

そういうわけにはいかない,exactにしてみた.効果はない

大文字にした,効果はない

componentでそのまま渡してるんだから,src/components/Works

からAppと並列のsrc/Worksにする

    <Route exact path='/App' component={App} />

これを追加して,deploy先でRouterが読まれているかのテストとする

動いていない

[https://reacttraining.com/react-router/web/guides/quick-start:embed:cite]

この例を見るとRouteの中にComponentを入れているので こっちらで試してみる

        <Switch>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/users">
            <Users />
          </Route>
          <Route path="/">
            <Home />
          </Route>
        </Switch>

このやり方ではErrorになったのでぼつ

https://codeburst.io/getting-started-with-react-router-5c978f70df91codeburst.io

このページのやり方

  <Router>
    <div>
      <Route exact path="/" component={App} />
      <Route path="/users" component={Users} />
      <Route path="/contact" component={Contact} />
    </div>
  </Router>

https://codeburst.io/getting-started-with-react-router-5c978f70df91

もerrorになる

crieit.net

Netlifyがredirectを弾いてるのが原因らしい?

/static/_redirects に以下の内容を記載。

/* /index.html 200

なのでdefaultのauto-deployからcliでのdeployにする必要が出てくる

mottox2.com

npm でcli をinstall

netlify linkでcurrent github projectにset

そしてstatic/ にさっきの_redirect fileをさくせい

... しかしこれをやってもRouteはできなかった....

とにかくNetlifyの問題なのか,firebase hosting している2ch

projectの方で見てみよう

2chにappそのままでrouterを追加

f:id:kei_s_lifehack:20200515005739p:plain

npm run build , firebase deploy

f:id:kei_s_lifehack:20200515010526p:plain

f:id:kei_s_lifehack:20200515010538p:plain

ダメだった,defaultのpageにredirectされてしまう...

exactにしたらいった!!!

f:id:kei_s_lifehack:20200515010805p:plain

firebase hostingでのrouting完了!!!!!ヨシ!!!!

神が教えてくださった.....

static/ ではなくbulid/に直接おいたらできた!!!!

docs.netlify.com

netlify public document にあったそうだ,そうかhostのredirectのページか....

なのでNetlifyでReact-routerを使う場合は

npm install netlify-cli -g

npm run build

cp _redirect builld/

netlify deploy

をする必要がある.

Hugo

Hogeの仲間の無意味語ではない!

そもそもSPAではrouteをする手間がかかる.

しかしhtml cssだけでかくと変更があったときに全身から血が吹き出して死ぬ.

それを防ぐための静的ジェネレーターにHugoがあるとたふみさんから

教えていただいた.

gohugo.io

未検証.dataからhtmlを生成できるようだ.

Excel 実践の授業 感想

## why 2020.05

Twitterbloggerは感想を書くことを条件に本がもらえるキャンペーンで,linkからformにblogのurlを入れて申し込んだら当選した

「当選は発想を持って変えさえていただきます」

なので連絡などは一切なかった

https://nihonzuno.co.jp/books-present-campaign/

how

職場に置いたが,まず紐とじなので開きやすくて好評だった

またさらっとauto fillから書かれていて使いやすい

文字も,職場での重複日報の検知作業に役立ち,MATCH()を使って

重複を見抜く式が書け,実務で役に立った

今後も更新していきます

またindirectなども分かりやすく例文を用いて書かれていて、ググる前のインデックスとしてパラパラ捲るのに重宝しています。

CSS Sidebar by React bootstrap Grid

why

HP Builderで作成された電気屋のHPの改修をやっている

非推奨であるiFrameのSideBarのNavigationをなるべく近いデザインで置き換える際に,Bootstrap Gridを採用したのでここに記す.

qiita.com

これがBootstrap Grid

なおRowとColを包括するタグは,Containerになる.

import {Container, Row, Col} from 'react-bootstrap';
......
  return (
    <Container>
      <Row>
        <Col>1 of 2</Col>
        <Col>2 of 2</Col>
      </Row>
      <Row>
        <Col>1 of 3</Col>
        <Col>2 of 3</Col>
        <Col>3 of 3</Col>
      </Row>
    </Container>
  );

簡単なGrid ならこれで組める

html css にクラスをつけるよりかなりわかりやすい.

この公式サンプルの通りに配置すると,上の1/2が下の1/3と同じ位置

上の2/2 が2/3と3/3の間の位置になる

Bootstrap4と言えど流石に最初から水色のいい感じのレイアウト は付いていないので,(Tableではない)

getbootstrap.com

これをみながらclassをつけて修飾する

weblion303.net

MUIの方がPaperなどがあるのが魅力的に見える.

getbootstrap.com

基本的に12分割で設定されている.

でspan3, 3/12枠を取れる感覚だ.

f:id:kei_s_lifehack:20200510105908p:plain

上のmarginを開けるのは

<Container className='my-4'>

であいた

これで

3 col 分の広さで横は揃った,あとは縦

paddingをつけたいが,Rowだけじゃ駄目で,Col一つ一つにつけない

先頭のColだけでもこうなる

[f:id:kei_s_lifehack:20200510112347p:plain]

    <Container className='my-5'>
      <Row>
        <Col className='py-5 bg-danger' 
          xs={3}>1 to 3, top-logo </Col>
        <Col className='py-5 bg-secondary' 
          xs={2}>4 to 5, big-logo</Col>
        <Col className='py-5 bg-danger' 
          xs={7}>6 to 13, text... </Col>
      </Row>
      <Row>
        <Col className='py-3 bg-info' 
          xs={3}>HOME BTN</Col>
        <Col className='py-3 bg-danger' 
          xs={2}>BLANK</Col>
        <Col className='py-3 bg-secondary' 
          xs={7}>BLANK</Col>
      </Row>
      <Row>
        <Col className='py-3 bg-info' 
          xs={3}>NEW INFO</Col>
        <Col className='py-3 bg-secondary' 
          xs={2}>SHOP 1 NAME</Col>
        <Col className='py-3 bg-danger' 
          xs={7}>SHOP 1 TEL</Col>
      </Row>
      <Row>
        <Col className='py-3 bg-info' 
          xs={3}>ABOUT WORK</Col>
        <Col className='py-3 bg-danger' 
          xs={2}>BLANK</Col>
        <Col className='py-3 bg-secondary' 
          xs={7}>BLANK</Col>
      </Row>

ついでに色もつけた

両サイドが空いているのはcontainerだからで

マックスにするにはcontainer-fluidにする必要がある

f:id:kei_s_lifehack:20200510130241p:plain

縦の結合

だが縦の結合ができなかった

素のCSSで書いていた時はclassごとにrow 1/2 col 3/2とかやっていたから, になるとわからん

start とendで合わせるか?

そして公式ドキュメントにはgird colは12がdefltとある

どうやらこのサイトによると

knowledge.cpi.ad.jp

これで列の改行ができて

f:id:kei_s_lifehack:20200510132517p:plain

www.dspt.net

このHTMLのtableのサイトだと結合されたセル にしろとある,だからcol spanをすればいいのか?

    <Col md={{span: 4}}>1 </Col>

のspanもxs={4}も変わらない

だがRowにSpanやxsをつけても盾が広がらない!!

offsetで隙間を開ければ!

      <Row>
        <Col className='py-3 bg-primary' 
          xs={3} offset={9} >HOME BTN</Col>
      </Row>

f:id:kei_s_lifehack:20200510134058p:plain

隙間が空いた!が,入らない!

medium.com

入れ子でcontainerと分ければ作れる!!!

f:id:kei_s_lifehack:20200510141253p:plain

ようやくProgressだ....

Col md 4の中にsidemenuを入れる

Col md 8の中にCardcontainerを入れる

logoの真ん中寄はd-blockでやった

sidebarはmapを駆使してわかりやすく書くことができた

const SideMenu = () => {
  const navText = [
    'NEW INFO', 'ABOUT WORKS', 'PARTS ORDER',
    'AIRCON CLEAN', 'LINKS',
  ];
  const navItems = navText.map((item, key) => 
      <Row>
        <Col className='py-3 bg-info ' >
          <h5 key={item}>{item}</h5>
        </Col>
      </Row>
  );
  return (
    <div>
      {navItems}
    </div>
  );
};
export default SideMenu;

これでmenuが増えた時も簡単に描ける


最終的に

    <Container className='my-5'>
      <Header />
      <Row>
        <Col className='py-3 bg-primary' 
          xs={3} >
          <SideMenu />
        </Col>
        <Col className='py-3 bg-secondary' 
          xs={9} >
          <Body />
        </Col>
      </Row>

2/12, 10/12, でSideMenuとBodyを分割し

import NavData from '../NavDataList'

const SideMenu = () => {
  const navItems = NavData.map((item, key) => 
      <Row key={item} className=''>
        <Col className='py-1 my-1 ' >
          <Button variant="light"
            href={item.link}
            size='lg'
            className='w-100'
            >{item.name}</Button>
        </Col>
      </Row>
  );
  return (
    <div>
      {navItems}
    </div>
  );
};

py-3で下にpaddingをつけながら,一つのColで出力することで

入れ子構造にして,SideMenuが実装できた.

f:id:kei_s_lifehack:20200613123129p:plain

そもそもSideMenuはGridで実装すべきではない?

中央揃えにしたlogoとずれるし,ただでさえ.containerで

サイドカットしてるのでSideMenuで2/12はとるとやばい

Make-2ch-log

まずAppの中身をCLEAR

Bootstrap4をnpmで食わせる

npm i bootstrap

4.4.1が入った

npm i react-bootstrap

これも必要?1.01が入った

import 'bootstrap/dist/css/bootstrap.min.css';

これをimportして

import Button from 'react-bootstrap/Button';

btnで試してみる

  <Button variant="primary">Primary</Button>{' '}

Appのrenderにこれを書いたら読み込まれた!

[f:id:kei_s_lifehack:20200507051109p:plain]

[https://react-bootstrap.github.io/components/table/:embed:cite]

Reactだとかなりsimpleにbootstrapがかける

[f:id:kei_s_lifehack:20200507051254p:plain]

しかし2chのUIはこれ

[f:id:kei_s_lifehack:20200507052547p:plain]

tableのUIはこれ

[f:id:kei_s_lifehack:20200507052610p:plain]

次の行にcontentsかけないし,columnの幅も調整できん

grid三つ書くしかないか?

[f:id:kei_s_lifehack:20200507120627p:plain]

思ったよりいい感じになった

import React from 'react';
import Writing from './components/Writing';

function App() {
  return (
    <div>
      <Writing/ >
    </div>
  );
}

export default App;

App側を簡単にかけるの便利だ

Database

まずはconsoleでfirestoreで

Add Firebase to Your AppのところでNick Name

firestoreを書いていく まずは src/Config/config.jsに

Add Firebase to Your AppのところでNick Name

npm i firebase

import firebase from 'firebase/app';

const firebaseConfig = ... {
apiKey = xxxxxx;

const firebaseApp = firebase.initializeApp(config);
export const firestore = firebaseApp.firestore();
.....
}

これをfirestoreとしてWritingでimport

refにuseStateを使ってみよう!!

dev.to

constructor直下に

this.ref = firebase.firestore().collection('notes');

で書いていたのを

const [ref, setRef] = useState[ firebase.firestore().collection('writings')];

に置き換える

useEffectがわからんが,どうやらcomponentWillMountに近いものらしい

[https://qiita.com/keiya01/items/fc5c725fed1ec53c24c5#%E8%89%AF%E3%81%84%E4%BE%8B-3:embed:cite]

この記事によると

useEffect(                                   
    () => {                                  
        const time = setInterval(() => {     
            dispatch({ type: "ADD_COUNT" }); 
        }, state.tick);                      
                                             
        return () => clearInterval(time);    
    },                                       
    [ state.tick ]                           
);                                           

これでstate.tickが変化するたびに「副作用」として処理を追加できるらしい

reactjs.org

function Example() {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

公式にはこのような記載がある.htmlのtitleも変更できるようだ

このコードでは[]に最後に入れてないから,何も入れてなければbrowser APIで何か 変数が更新されたのを検知してuseEffectをうごかすのだろうか.

TypeError: storeRef.onShapshot is not a function (anonymous function) src/components/Writing.jsx:37 34 | 35 | useEffect( 36 | () => {

37 | let unsub = storeRef.onShapshot( | ^ 38 | update 39 | ); 40 | }

storeRef.onShapShotがuseEffectではとれない....

storeRefの中身は確認してある.hooksでclassのやり方はできないようだ

blog.logrocket.com

全部はわからんがここのコードを使ってみる

export const createWrintings = (writings) => {
  return storeRef.add({
    created: firebase.firestore.FieldValue.serverTimestamp(),
    content: writings,
  });
};

create, addは簡単に作れた.stateは使わないようだ

SHOWができないから

qiita.com

これを使ってみる

github.com

react-firebase-hooks というツールを使う

npm install --save react-firebase-hooks

Writing.jsxにはいつもの

import firebase from 'firebase/app';
import { firestore } from '../Config/config';

の他に

import {useCollectionData} from 'react-firebase-hooks/firestore';

をしてさっきnpm i したのを読んで

  const [values, loading, error,] = useCollectionData(
    ref, {idField: 'id'});

で設定する

  if(loading) {
    return <div>Loading...</div>
  }
  if(error) {
    return <div>{`Error: ${error.message}`}</div>
  }

loading, errorではこれらを返し

  return (
    <ul>
      {values.map(value => (
        <li key = {value.id}>{value.content}</li>
      ))}
    </ul>
  )

return ではvalueをmapするだけ doc...とか一切必要がない

これだけでfirestore collectionからDOMに書き込めた

f:id:kei_s_lifehack:20200514012525p:plain

valuesをcllすると

(2) [{…}, {…}]
0: {created_at: t, content: "俺みたいな中3でグロ見てる腐れ野郎、他に、いますかっていねーか、はは", id: "KwONQGM2AyLohkGOTF3u"}
1: {created_at: t, content: "初カキコ,ども...", id: "LIGRzMJJdxM1pJAo5R3L"}
length: 2
__proto__: Array(0)

ちゃんと入っている!!!これをcreated_atでsortすれば行けそうだ.

idFieldでidを取得するところがポイントです。

と書いてある通りに,doc.idがdoc.data()と並列で入っている!!


また,記事のNewTodoの通りに

const Add = () => {
  const [content, setContent] = useState('');
  const [pending, setPending] = useState(false);

  const add = async () => {
    setContent('');
    setPending(true);

    try {
      await ref.add({
        content,
        created_at: firebase.firestore.FieldValue.serverTimestamp(),
      });
    }
    finally {
      setPending(false);
    }
  }

useStateを使ってcontentを空のstr, pendingをfalseでstateとして初期化

そして追加btnが押された時のaddの処理を書く.

asyncを噛ませてcontentを空にし,実行中ということでpendingをtrueに

tryではawaitが使われるのでこちらが先になるのか?

setContent('')が行われていないのでcontentは残っている.これが先に refにcreated_atとともに追加される

そしてtryが終わった後にpendingをfalse, NOに書きかえる

その後async前半が処理されてinput valueのcontentが空になり pendingがfalseになる.

このaddを

  return (
    <div>
      <input 
        value = {content} 
        onChange={e => setContent(e.target.value)}
      />
      <button
        onClick={add}
      >
        Add
      </button>
        {pending && 'Pending...'}
    </div>

returnでinputを作り,valueには常にcontentを置き, onChangeにsetContentをしてe.target.valueをおく.

btnのonClickでaddがfireするように仕込み,

その下にはpendingがtrueの時のみ出るようにする

このComponentをAppで読み込むことによって

追加機能のあるinputとbtnが配備された.

Wesのよりかなりシンプルだ

どのcomponentでもrefは使っているので,Appで呼び出してpropsで渡そうか

しかしありえんほど簡単に


毎回firestoreをconsolelogで使用しているのもおかしいので改善策を感がてみた

config のままexportして,各自のcomponentでinitする作戦は

objのconfigをうまくconfigとしてexportできずにerror

import config from '../Config/config';

firebase.initializeApp(config);

これでうまくいきそうだが,これでもno -usedになってしまう

App側で済ますのも無理だった

これは仕方ないのかもしれない

f:id:kei_s_lifehack:20200514034048p:plain

export const firestore = firebase.initializeApp(config);

をconfig.jsに書いて

import {firestore} from '../Config/config';

をfirestore使う全てのcomponentに書くのは避けられないようだ;;;;;;

kaede-0902ch.web.app

timestamp 出ないけど大まかなレイアウトは下

sort

timestampの値でsortがしたい

[1, 2,3, ] ならarr.sortで簡単だがarrのobjが必要

created_atの中身は

created_at: t
nanoseconds: 964000000
seconds: 1589391378

である

これを普通に出そうとしたらめっちゃ詰まった

kei-s-lifehack.hatenablog.com

まぁ2020.05.21に解決して,例外処理挟んで出せるようになった, UIも書いた

f:id:kei_s_lifehack:20200521213413p:plain

ここで

React使っててなぜXSSが防げてるのかなんもわからん

dangerouslySetInnerHTMLを使うとXSSできるようになりますよ!() やれるもんならやってみて下さいよ! Add関数壊れてるわよ

f:id:kei_s_lifehack:20200521214339p:plain

おもちゃかコレェ!!!!!!!(言いたかっただけ)

www.youtube.com

動かしてなぜ動かないかわからん...

qiita.com

短くかける!!!と思ってここのsetTitleのところを流用してadd関数を作った

import React, { useState } from "react";
import {Col, Row,} from 'react-bootstrap';
import {Form} from 'react-bootstrap';
import {Button} from 'react-bootstrap';
import firebase from 'firebase/app';
import { firestore } from '../Config/config';



const ref = firebase.firestore().collection('writings');

const Add = () => {
  const [content, setContent] = useState('');
  const [pending, setPending] = useState(false);

  const add = async () => {
    setContent('');
    setPending(true);

    try {
      await ref.add({ 
        content: content,
        created_at: 
          firebase.firestore.FieldValue.serverTimestamp,
      });
    }
    finally {
      setPending(false);
    }
  }
  return (
    <div>
    <Form>
      <Row>
        <Col md = {7}>
          <Form.Control 
            placeholder='write here' 
            value = {content} 
            onChange={e => setContent(e.target.value)}
          />
        </Col>
        <Col md = {5}>
          <Button variant="primary" 
            type="submit" onClick={add}
            >
            Submit
          </Button>
        </Col>
      </Row>
    </Form>
    {pending && 'Pending...'}
    </div>
  )
};


export default Add;

これを自分のちんちんで...じゃなくて自分で入れてbuttton押すと, 動いているように見えるが中身が入らない

エラーも出ないしわからない....

最初は動いてたもん,自分で自分のちんちん舐めたいって入れないし...

そんなに身体が柔らかくないので...(そういう問題?)

firestore追加されない問題

2020.05.30. 解決を図る.

const ref = firebase.firestore().collection('writings');

const Add = () => {
  const [content, setContent] = useState('');
  const [pending, setPending] = useState(false);

  const add = async () => {
    setContent('');
    setPending(true);

    try {
      console.log('adding');
      await ref.add({ 
        content: content,
        created_at: 
          firebase.firestore.FieldValue.serverTimestamp,
      });
    }
    finally {
      setPending(false);
    }
  }

こうしてconsole.log addingは一瞬見える.

追加中に画面が切り替わっているのだろうか?

ちんちんが追加された時はそういえばBootstrapは使っていなかった

このBtnが何か悪いのだろうか

f:id:kei_s_lifehack:20200530045728p:plain

Firebase CLI で React App を Hosting する

Firebase + ReactのHosting やり方

なぜ?

よく忘れるからドキュメンテーション

Console of Firebase ( Browser )

Firebase consoleでcreate project

そして真っ先にdatabaseからcloud firestoreを作成する

ここでlocationの選択が出てくる, asia-northeastを選択

これができてないとRDBGCPしか使えなくなる

また消して作り直す場合は、trash から消えるのを待つ必要があるので

30日同じ名前を使えないので注意。

Terminal

ターミナルで適当なディレクトリを作成して

npm install -g firebase-tools

firebase-tools を install する

npm i firebase ではない

firebase login

これで Chrome が開いてログイン処理できる。

firebase init

TUI設定開始

Firestore, Hositing を選択

use an existing projectを選択

使うプロジェクトを選択する

? What do you want to use as your public directory? public
? Configure as a single-page app (rewrite all urls to /index.html)? Yes
✔  Wrote public/index.html

i  Writing configuration info to firebase.json...
i  Writing project information to .firebaserc...
i  Writing gitignore file to .gitignore...

✔  Firebase initialization complete!

これで init が終わった。

firebase deploy

これでデプロイできる

f:id:kei_s_lifehack:20200505011718p:plain

ソースを見てみる

生成されたソースを見ると、app, auth, database, message, storage,

そして init がローカルな処理?

    <script src="/__/firebase/7.14.2/firebase-app.js"></script>
    <script src="/__/firebase/7.14.2/firebase-auth.js"></script>
    <script src="/__/firebase/7.14.2/firebase-database.js"></script>
    <script src="/__/firebase/7.14.2/firebase-messaging.js"></script>
    <script src="/__/firebase/7.14.2/firebase-storage.js"></script>
    <!-- initialize the SDK after all desired features are loaded -->
    <script src="/__/firebase/init.js"></script>

webで見れる.拡張子はnetlifyと同じ.app

f:id:kei_s_lifehack:20200505012015p:plain

ソースを書き換えると反応した

React

medium.com

これを参考にする

portfolioと言う名のprojectならまずfirebase設定するときに作った

code/portofolio/で npx create react app portfolio

cd portfolio/

親dirにあるpublic/ はindex.htmlしかないからrm -rf

残りを全てmv * ..で持ってくる

package.jsonはfirebaseの方にはないからNO CONFLICT

中の方の node_modules/ は放棄

とりあえずportfolio/ でnpm i (package.jsonのdataからreact動かすため?)

そしてnpm startでlocalでreactが動作する

f:id:kei_s_lifehack:20200610194029p:plain

firebase.jsonのpublic: publicをbuild/に書き換える

そしてnpm run build, firebase deploy

これでbuild先で動く.(https://portfolio0902.web.app/)

f:id:kei_s_lifehack:20200610194651p:plain

Database crud

別の記事に書く

懸念点

spark(free)planでは作成数に上限がある……

PRJを作る度にLimitに近づいているカウントがされていく。

これは既存の適当に乱立したPRJを全て削除してもリセットされない。

削除したprojectが30days立つまで減るのを待つ必要がある.

FTP SoftでのHPのupload

why, なぜFTP?

職場のhogedenki.comが消滅した.どのサービスを使っていたかも不明だ.

そこでサブで使われていたHP builderで94年とかに作られたwin96らしいカラフルなサイトを更新することになり,いにしえの書類が発掘されて最終的に接続に成功した.

職場のHPがFTPというソフトを使った方式だった.

結局FFFTPはダメで,winSCP を使用した.

site name, id, passなどでloginするとGUIで,右半分がServer, 左がlocalのdirになる.

これで適当にVScodeとかで開いてpushすると反映される.

git を使いなれている私にはFTPソフトでのpushは非常に面倒だ,

まず私がMacで開発したものをgithubにあげて後輩くんにDLさせてFTPさせる方式では,個人情報のあるサイトデータをpublicにするわけには行かないので面倒

またNetlifyみたいにauto buildしてくれなく,bulidしたもののエントリーポイントをどうするかも難しい

フォロワーにCUIでやれる方法もあると教えてもらった

girigiribauer.com

passwordを私のpcにも打ち込んでいいならこれで実装しよう...

npm build

f:id:kei_s_lifehack:20200625124935p:plain

buildしたreact-appはopen index.htmlで開いても動かない.

localhostでnpm startするか,NetlifyやFirebaseのserverに上げれば

動いた.

しかしFTPの静的環境ではそんなことはやってくれないだろう.

なのでbuild/index.htmlを開いてreact-appが正常に動いてる状況で

File Trasportする必要が出てきた

qiita.com

こちらに書いてあるように

package.json

"homepage": "."

を追加してもだめだった.

React Material-UIを使ってみた

why

職場のサイトを作ることになって,headerを作るのに採択した

medium.com

mediumを参考にする

npm install @material-ui/core --save

npm i contentful --save

import React from 'react'
import AppBar from '@material-ui/core/AppBar'
import Toolbar from '@material-ui/core/Toolbar'
import Typography from '@material-ui/core/Typography'
const NavBar = () => {
    return(
        <div>
        <AppBar position="static">
            <Toolbar>
                <Typography variant="title" color="inherit">
                React & Material-UI Sample Application
                </Typography>
            </Toolbar>
        </AppBar>
        </div>
    )
}
export default NavBar;

NavBarのコードをコピペ

dependenciesのpackage.jsonも含めてpushするとできた

だが公式ドキュメントを読んでも複雑で,自分で組み合わせられそうにない

github.com

これはこのまま使えるらしい?

mebee.info

github.com

これならそのままcopyして使えるらしいが,Starbarがresolveできなかった..消したら動いた.

Androidの情報が多い

ここからパーツのまとまりをみていく

material-ui/Pricing.js at master · mui-org/material-ui · GitHub

Appbarを見ると

      <AppBar position="static" color="default" elevation={0} className={classes.appBar}>
        <Toolbar className={classes.toolbar}>
          <Typography variant="h6" color="inherit" noWrap className={classes.toolbarTitle}>
            Company name
          </Typography>
          <nav>
            <Link variant="button" color="textPrimary" href="#" className={classes.link}>
              Features
            </Link>
            <Link variant="button" color="textPrimary" href="#" className={classes.link}>
              Enterprise
            </Link>
            <Link variant="button" color="textPrimary" href="#" className={classes.link}>
              Support
            </Link>
          </nav>
          <Button href="#" color="primary" variant="outlined" className={classes.link}>
            Login
          </Button>
        </Toolbar>
      </AppBar>

になっていて

AppBar, Toolbar, Typography, Link, Button,

が使われている,全てimportする

classNameが必要,useStylesでかなり定義されているからその

import { makeStyles } from '@material-ui/core/styles';

も入れて先に変数で宣言しておく必要がある

const useStyles = makeStyles((theme) => ({
  '@global': {
    ul: {
      margin: 0,
      padding: 0,
      listStyle: 'none',
    },
  },
  appBar: {
    borderBottom: `1px solid ${theme.palette.divider}`,
  },
.......

そしてfunction App()のなかに

const classes = useStyles();

これを宣言

もちろんこれも必要

npm install @material-ui/core

これでこのコードだけで

const useStyles = makeStyles((theme) => ({
  '@global': {
    ul: {
      margin: 0,
      padding: 0,
      listStyle: 'none',
    },
  },
  appBar: {
    borderBottom: `1px solid ${theme.palette.divider}`,
  },
  toolbar: {
    flexWrap: 'wrap',
  },
  toolbarTitle: {
    flexGrow: 1,
  },
  link: {
    margin: theme.spacing(1, 1.5),
  },
}));

function App() {
  const classes = useStyles();
  return (

このheaderが実装できた

f:id:kei_s_lifehack:20200504160948p:plain

ではこのUIを動かしてみよう.サンプルテンプレを見せて言われたのはheaderが小さい,文字が小さいだったからそれを変えてみる

下記では全て変化がない.

  appBar: {
    padding: '100px',
  },
    minHeight: 300,

    paddingTop: theme.spacing(5),

      <AppBar position="static" color="default" elevation={0}
        height='201%' >

ul globalのpaddingを消してもダメだ

この数値を変えたら動いた!

  link: {
    margin: theme.spacing(1, 1.5),
  },

だが,Appbarに適用しても変化がない

defaultの大きさはこれだ

f:id:kei_s_lifehack:20200504170502p:plain

そもそもAppbar, Toolbar, ToolbarTitle, linkの関係性ってなんだ?

とりあえずlink全てにmgnを渡すことによってくっつくことをpreventしている

toolbarでspacingの2nd argを増やすと左に寄る (mgn rightか?)

    margin: theme.spacing(0, 20),

f:id:kei_s_lifehack:20200504170619p:plain

この時tool titleのいちは変わらないから,この二つは独立している.

当然1st argを増やすと下に膨らむ.

margin: theme.spacing(20, 0),

[f:id:kei_s_lifehack:20200504170731p:plain]

よってこれでheader barの大きさを調整できる.

次は左側にlogoを仕込みたい.

なぜCompany nameが真ん中になっているのかは

TypograhyとLinkの違いだ

[http://yucatio.hatenablog.com/entry/2018/12/20/090547:embed:cite]

このサイトを見るとLinkにlogоを入れて

      <Link to='/'>
        <img src={logo} alt="TODODO(トドド)" height="36" width="auto"/>
      </Link>

inlineで大きさを調整している

このサイトを見ると

www.reddit.com

import AppBar from "@material-ui/core/AppBar";
import Grid from "@material-ui/core/Grid";
import { makeStyles } from "@material-ui/core/styles";
import Toolbar from "@material-ui/core/Toolbar";
import React from "react";
import { Tabs } from "@material-ui/core";
import Tab from "@material-ui/core/Tab";

const useStyles = makeStyles({
  root: {
    flexGrow: 1
  },
  logo: {
    width: 135,
    height: 43.54
  }
});

const Header = () => {
  const classes = useStyles();
  const [value, setValue] = React.useState(0);

  return (
    <nav className={classes.root}>
      <AppBar position="static" color="default">
        <Toolbar>
          <Grid justify={"space-between"} container>
            <Grid xs={1} item>
              <img
                className={classes.logo}
                src={
                  "https://upload.wikimedia.org/wikipedia/commons/a/a7/React-icon.svg"
                }
                alt="Bosch Logo"
              />
            </Grid>
            <Grid xs={4} item>
              <Grid container justify={"center"}>
                <Tabs
                  onChange={(e, v) => setValue(v)}
                  value={value}
                  aria-label="Navigation Tabs"
                >
                  <Tab label={"page 1"} />
                  <Tab label={"page 2"} />
                </Tabs>
              </Grid>
            </Grid>
            <Grid item xs={1} />
          </Grid>
        </Toolbar>
      </AppBar>
    </nav>
  );
};

export default Header;

Grid xs 1, 4, で割合を調節してるっぽい?

をコンテナとして

にimgのlogoをuseStylesでwidth: 135,height: 43.54, で入れて

それの後に

のなかに

を入れて

でlogic指定している中に

を二つ

その後に

で空間調整している.

だからこの調節コードを消すと

f:id:kei_s_lifehack:20200506205339p:plain

右にずらされる

f:id:kei_s_lifehack:20200507030306p:plain

よし!!と思ったが

f:id:kei_s_lifehack:20200507030447p:plain

自動でresponsiveにしてくれるわけではなかった....

このままではCorp Siteには採用できない

media queryごとにgiridで書くか???

Grid

blog.logrocket.com

この記事もわかりやすい

material-ui.com

f:id:kei_s_lifehack:20200507031148p:plain

とりあえずGridはわかりやすい.

f:id:kei_s_lifehack:20200507031246p:plain

ここを見るとflex-start, center, flex-endがよくわかる

headerで左右に分ける時はこれを分ければいいわけだ.

さっきのredditのcodeはspace-between でlogoを左において

距離をとって,flex-endでTabを右ヅメにしたわけだ.

また,paddingはtheme.spacing(2)で取るのが一般的らしい.

普通に入れるカードはPaper, 文字を入れるのはTypography.

自動でmedia queryをやってくれるGridは見つからなかったが

material-ui.com

Containerで幅をsm, smallに制限して

twicall.net

きゃりーさんの新作のように

元から狭い幅で作ってしまえば一つのlayoutですむかもしれない.

いや,流石にCorp Siteでこれは狭すぎるか....

Reactでmedia queryごとにcssを分けて書くのはどうやるんだろうか?

material.io

設計としてはこの記事がわかりやすい

table

f:id:kei_s_lifehack:20200507034036p:plain

Validateがうまくいっていればスマフォでもいい感じになるはずの

moneylogのこれは, bootstrap4のtable-responsiveで作ったが

Table React component - Material-UI

MUIには相当するものはなかった.

ただSortなど,使いこなせれば相当richだと思う.