脳内メモリ使わず初期設定（create-react-app）その1

その２（stylus実験…動かない）
https://qiita.com/DaisukeNishi/items/57cb3a440ddfb876ee9a
その３
https://qiita.com/DaisukeNishi/items/78bdb0ec6af9aea204d2

※自分用`boilerPlate`作ればいいじゃん`git clone`一発だよと思うじゃないですか。
一応、写経も兼ねて反芻してるです。

「感謝の正拳突き1日1万回」...じゃないですが、
毎日環境構築を反芻してたら型として覚えられると思った。
変な型が身についてしまったらゴメンなさい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216132/fa00a26d-d52f-fde8-5306-81ca2f5ce167.png)

(↓グローバルインストールは初回のみ)

```
npm i -g create-react-app
sudo npm install eslint -g
sudo npm i -g eslint-plugin-react
```
プロジェクト(名前例)`react_1231`を作る。

```shell
create-react-app react_`date '+%m%d'`
cd react_`date '+%m%d'`
```
`git`初期化

```
git init
open .gitignore
```
セーブポイントは除外。

```
.history
```
リモートを作っておく。

```
open https://github.com/
open https://bitbucket.org/
```
プッシュする。

```
git remote add origin (GitのURL)
git push -u origin master
```
設定オーバーライドの鉄板。

```
yarn add react-app-rewired customize-cra
touch config-overrides.js
open config-overrides.js
```

```config-overrides.js
const { override,useBabelRc,useEslintRc,disableEsLint} = require("customize-cra");
module.exports = override(
  useBabelRc(".babelrc.json"),
  useEslintRc(".eslintrc.json"),
  //disableEsLint()
);
```
NPMスクリプトを書き換える。

```
open package.json
```
```package.json
  "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-app-rewired eject"
  },
```
CSSのプラグインを入れる

```
yarn add styled-jsx
yarn add styled-jsx-plugin-sass
//yarn add styled-jsx-plugin-stylus //（未検証）
yarn add node-sass
//yarn add stylus stylus-loader
```
設定ファイルを作る

```
touch .babelrc.json
```
```
open .babelrc.json
```
```.babelrc.json
{
  "presets": [
    "react-app"
  ],
  "plugins": [
    ["styled-jsx/babel",
      { "plugins": ["styled-jsx-plugin-sass"] }
      //{ "plugins": ["styled-jsx-plugin-stylus"] }　//どっちか選ぶ
    ]
  ]
}
```
```
eslint --init

>To check syntax and find problems
>JavaScript modules (import/export) 
>React
Typescript? N
Where code run?
◎ Browser
◎ Node
What format?
>JSON
eslint@latest install? Y
```
`yarn start`したらつけっぱなし。終了は`Ctrl+C`

```
yarn start
```
エラーなければ、テンプレートを編集する。


サンプルの「App.js」を編集する

```
open App.js
```

```src/App.js
import React, { Fragment } from 'react';
import logo from './logo.svg';
function App() {
  return (
    <Fragment>
      //HTML
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <p>
            Edit <code>src/App.js</code> and save to reload.
          </p>
          <a
            className="App-link"
            href="https://reactjs.org"
            target="_blank"
            rel="noopener noreferrer"
          >
            Learn React
          </a>
        </header>
      </div>
      //CSS
      <style jsx>{`
        .App {
          text-align: center;
        }
        .App-logo {
          height: 40vmin;
          pointer-events: none;
        }
        @media (prefers-reduced-motion: no-preference) {
          .App-logo {
            animation: App-logo-spin infinite 20s linear;
          }
        }
        .App-header {
          background-color: #282c34;
          min-height: 100vh;
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
          font-size: calc(10px + 2vmin);
          color: white;
        }
        .App-link {
          color: #61dafb;
        }
        @keyframes App-logo-spin {
          from {
            transform: rotate(0deg);
          }
          to {
            transform: rotate(360deg);
          }
        }
      `}</style>
    </Fragment>
  );
}
export default App;
```
子コンポーネントのテンプレを作る

```
touch Template.js
```
```src/Template.js
import React from 'react'
import { connect } from 'react-redux'

const render = () => {
  return (
  <Fragment>
    <div className="">

    </div>
    <style jsx>{`

    `}</style>
  </Fragment>
  )
}

const mapState = (state) =>{
  return {

  }
}

const mapDispatch = (dispatch) => {
  return {

  }
}

export default connect(mapState, mapDispatch)(render)
```
ディレクトリの構造をやや過剰に作る。

```shell
mkdir -p src/components/common/common src/components/common/home src/components/common/list src/components/common/detail src/components/pc/common src/components/pc/home src/components/pc/list src/components/pc/detail src/components/sp/common src/components/sp/home src/components/sp/list src/components/sp/detail src/assets/img src/scss src/views src/components/pc/notfound src/components/sp/notfound src/components/pc/about src/components/sp/about src/components/pc/company src/components/sp/company src/components/pc/policy src/components/sp/policy src/components/pc/terms src/components/sp/terms src/components/pc/contact src/components/sp/contact
```
ディレクトリにTemplate.jsを埋めていく。

```
cd src
rm App.css
find . -name "*" -type d -exec cp Template.js {} \;
```
不要なやつは消す。

```
rm Template.js scss/Template.js assets/Template.js assets/img/Template.js components/Template.js 
 components/common/Template.js components/pc/Template.js components/sp/Template.js
```
```
cd  ../
```
`redux`に必要となるプラグインを入れる

```
yarn add axios immer react-app-polyfill react-router-dom react-transition-group react-redux redux redux-devtools redux-thunk
```
`IE`対応あるだろうから`polyfill`と`autoprefixer`は忘れずに

```package.json
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not ie <= 11", //←コレ追記
      "not op_mini all"
    ],
```
`redux`で必要な`store`を作る

```
mkdir src/store
touch src/store/index.js src/store/actions.js src/store/reducer.js
open src/store/index.js
```
```src/store/index.js
import { createStore, applyMiddleware, compose } from 'redux'
import reducer from './reducer'
import * as actions from './actions'
import thunk from 'redux-thunk'

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose

const store = createStore(
  reducer,
  composeEnhancers(applyMiddleware(thunk))
)
export default store
export { reducer, actions }
```

```
open src/store/actions.js
```
```src/store/actions.js
import axios from 'axios'

export const showSide = () => ({
  type: 'showSide'
})

export const hideSide = () => ({
  type: 'hideSide'
})

export const changeL = () => ({
  type: 'changeL'
})

export const showLR = (val) =>({
  type: 'showLR',
  val
})
```


```
open src/store/reducer.js
```
```src/store/reducer.js
import produce from "immer"
import { combineReducers } from 'redux'

const defaultState = {
  sideBar: false,
  blurStyle: {},
  cover: false
}

const mutations = {
  showSide (state, action) {
    return produce(state, (state) => {
      state.sideBar = true
      state.cover = true
      state.blurStyle = {transform: 'translateX(15rem)', filter: 'blur(3px)'}
    })
  },
  hideSide (state, action) {
    return produce(state, (state) => {
      if (state.LR) {
        state.LR = false
      } else {
        state.sideBar = false
      }
      state.cover = false
      state.blurStyle = {}
    })
  }
}

const store = (state = defaultState, action) => {
  if (mutations[action.type]) {
    return mutations[action.type](state, action)
  }
  return state
}

export default combineReducers({
  store
})
```

```
open src/index.js
```
`src/index.js`を書き換える。`serviceworker.js`下に追記する、`export`は書き換える

```src/index.js
//（省略）
import store from './store'
import { Provider } from 'react-redux'

ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'))
```
ブラウザ表示にエラーが出てないか確認。

##ヘッダ・フッター・メニューつける

```
touch src/components/common/common/Header.js
open src/components/common/common/Header.js
```
```src/components/common/common/Header.js
import React, {Fragment} from 'react'
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
import { actions } from '../../../store'

const render = (props) => {
  return (
    <Fragment>
      <div className="header">
        <span className="button" onClick={props.showSide}>
          ≡
        </span>
        <Link to='/'>
          <span className="title">react-app</span>
        </Link>
      </div>
      <style jsx>{`
        .header{
          position: fixed;
          top: 0;
          right: 0;
          left: 0;
          z-index: 5;
          background-color: #fff;
          box-shadow: 0 3px 15px 0px #0001;
          vertical-align: middle;
          color: #02b3e4;

          .button{
            height: 4rem;
            line-height: 4rem;
            display: inline-block;
            padding: 0 1rem;
            text-align: center;
            font-weight: 800;
            font-size: 1.2rem;
          }
          
          .title{
            font-size: 1.4rem;
            font-weight: bold;
            margin-left: 1.5%;
            height: 3rem;
            line-height: 3rem;
          }
        }
      `}</style>
    </Fragment>
  )
}

const mapState = (state) =>{
  return {
  }
}

const mapDispatch = (dispatch) => {
  return {
    showSide() {
      dispatch(actions.showSide())
    }
  }
}

export default connect(mapState, mapDispatch)(render)
```
サイドメニューを用意。

```
touch src/components/common/common/Menu.js
open src/components/common/common/Menu.js
```

```src/components/common/common/Menu.js
import React, {Fragment} from 'react'
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
import { actions } from '../../../store'

const render = (props) => {
  return (
    <Fragment>
      <div className="bar">
        <div className="btn-wrapper">
          <Link to="/">
            <span type="button" className="btn btn-light" onClick={props.hideSide}>閉じる</span>
          </Link>
        </div>
      </div>
      
      <style jsx>{`
        .bar{
          position: fixed;
          top: 0;
          bottom: 0;
          left: 0;
          width: 15rem;
          background-color: #fff;
          padding-top: 2rem;
          box-shadow: 0px 2px 20px #0003;
          z-index: 6;

          .btn-wrapper{
            height: 4.5rem;
            line-height: 4.5rem;
            text-align: center;
          }
        }
      `}</style>
    </Fragment>
  )
}

const mapState = (state) =>{
  return {
  }
}

const mapDispatch = (dispatch) => {
  return {
    hideSide () {
      dispatch(actions.hideSide())
    }
  }
}

export default connect(mapState, mapDispatch)(render)
```
フッターを準備

```
touch src/components/common/common/Footer.js
open src/components/common/common/Footer.js
```
```src/components/common/common/Footer.js
import React,{Fragment} from 'react'
import { connect } from 'react-redux'

const Footer = () => {
  return (
    <Fragment>
      <div className="footer">
        Copyright@XXX-XXX co,Ltd.
      </div>
      <style jsx>{`
        .footer{
          color: #777;
          margin-top: 0rem;
          height: 4rem;
          line-height: 4rem;
          text-align: center;
          background-color: #efefef;
        }
      `}</style>
    </Fragment>
  )
}

export default connect(null, null)(Footer)
```
`App.js`を`redux`対応版に書き換える

```src/App.js
import React, { Fragment } from 'react';
import { connect } from 'react-redux'
import logo from './logo.svg';

import { BrowserRouter }  from 'react-router-dom'
import { actions } from './store'

import Header from './components/common/common/Header'
import Footer from './components/common/common/Footer'
import Menu from './components/common/common/Menu'

import { CSSTransition } from 'react-transition-group'

function App( props ) {

  return (
    <Fragment>
      <BrowserRouter>
        {/* HTML */}
        <div className="App">
          <Header></Header>
          <header className="App-header">
            <img src={logo} className="App-logo" alt="logo" />
            <p>
              Edit <code>src/App.js</code> and save to reload.
            </p>
            <a
              className="App-link"
              href="https://reactjs.org"
              target="_blank"
              rel="noopener noreferrer"
            >
              Learn React
            </a>
          </header>
          <Footer></Footer>
          <CSSTransition in={props.sideBar} timeout={300} classNames="fade" unmountOnExit>
            <Menu />
          </CSSTransition>
        </div>
        {/* CSS */}
        <style jsx>{`
          .App {
            text-align: center;
          }
          
          .App-logo {
            height: 40vmin;
            pointer-events: none;
          }
          
          @media (prefers-reduced-motion: no-preference) {
            .App-logo {
              animation: App-logo-spin infinite 20s linear;
            }
          }
          
          .App-header {
            background-color: #282c34;
            min-height: 100vh;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            font-size: calc(10px + 2vmin);
            color: white;
          }
          
          .App-link {
            color: #61dafb;
          }
          
          @keyframes App-logo-spin {
            from {
              transform: rotate(0deg);
            }
            to {
              transform: rotate(360deg);
            }
          }
        `}</style>

      </BrowserRouter>
    </Fragment>
  );
}

const mapState = (state) =>{
  return {
    sideBar: state.store.sideBar,
  }
}

const mapDispatch = (dispatch) => {
  return {
    hideSide () {
      dispatch(actions.hideSide())
    }
  }
}

export default connect(mapState, mapDispatch)(App)
```

気がつけば`sass`とか`redux`で書ける環境ができてると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216132/9c80d9d4-c6a2-d7a8-b222-ba6763a91a1f.png)

####参考にしたもの：
https://github.com/guts111/MyForum-React