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

react最初の設定を反芻。徐々に改善していくスタイル。。

その1
https://qiita.com/DaisukeNishi/items/c8982546c803d2c5dc99
その２
https://qiita.com/DaisukeNishi/items/57cb3a440ddfb876ee9a

##環境構築を反芻して覚える。
![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
```
##yarnで必要なもの一通り

```
yarn add react-app-rewired customize-cra styled-jsx axios immer react-app-polyfill react-router-dom react-transition-group react-redux redux redux-devtools redux-thunk node-sass styled-jsx-plugin-sass
```
##空ディレクトリ作成　

```
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 src/store
```
##空ファイル作成

```
touch config-overrides.js .babelrc.json src/Template.js src/components/common/common/Header.js src/components/common/common/Menu.js src/components/common/common/Footer.js src/store/index.js src/store/actions.js src/store/reducer.js
```

##テンプレート作成
```
open src/Template.js
```
```src/Template.js
import React,{Fragment} from 'react'
import { connect } from 'react-redux'

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

    </div>
    <style jsx>{`

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

// eslint-disable-next-line no-unused-vars
const mapState = (state) =>{
  return {

  }
}

// eslint-disable-next-line no-unused-vars
const mapDispatch = (dispatch) => {
  return {

  }
}

export default connect(mapState, mapDispatch)(render)
```
##テンプレート配置

```
cd src
find . -name "*" -type d -exec cp Template.js {} \;
cd ../
rm src/App.css src/scss/Template.js src/assets/Template.js src/assets/img/Template.js src/components/Template.js src/components/common/Template.js src/components/pc/Template.js src/components/sp/Template.js src/store/Template.js
```
##CRA設定ファイル編集

```
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()
);
```
##package.json編集

```
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"
  },
  //（中略）
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not ie <= 10", //追加
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }

```
##babel設定編集

```
open .babelrc.json
```
```.babelrc.json
{
  "presets": [
    "react-app"
  ],
  "plugins": [
    ["styled-jsx/babel",{ "plugins": ["styled-jsx-plugin-sass"]}]
  ]
}
```
##eslint初期設定

```
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
```
最後に"extends"の内容を編集する

```
"extends": [
    "react-app"
],
```


##redux用のstoreファイル編集

```
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,
  L: true,
  LR: 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
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import store from './store'
import { Provider } from 'react-redux'

ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'))
serviceWorker.unregister();
```
##コンポーネント編集
```
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>
  )
}

// eslint-disable-next-line no-unused-vars
const mapState = (state) =>{
  return {
  }
}

// eslint-disable-next-line no-unused-vars
const mapDispatch = (dispatch) => {
  return {
    showSide() {
      dispatch(actions.showSide())
    }
  }
}

export default connect(mapState, mapDispatch)(render)
```
```
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>
  )
}

// eslint-disable-next-line no-unused-vars
const mapState = (state) =>{
  return {
  }
}

// eslint-disable-next-line no-unused-vars
const mapDispatch = (dispatch) => {
  return {
    hideSide () {
      dispatch(actions.hideSide())
    }
  }
}

export default connect(mapState, mapDispatch)(render)
```
```
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)
```
```
open src/App.js
```
```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>
  );
}

// eslint-disable-next-line no-unused-vars
const mapState = (state) => {
  return {
    sideBar: state.store.sideBar,
  }
}

// eslint-disable-next-line no-unused-vars
const mapDispatch = (dispatch) => {
  return {
    hideSide () {
      dispatch(actions.hideSide())
    }
  }
}

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