引き続き、Udemy講座「フロントエンドエンジニアのための React ・ Redux アプリケーション開発入門」で学習しています。

React Hooksが登場してからClassコンポーネントから関数コンポーネントに置き換わる、であるとか、Recoilが出てからReduxいらないのでは?などが話題に上がっていますが、まずは基礎から抑えていこうと考えています。

Vueの方が簡単なのは確かに同意ですが、Reactの方が柔軟な感じがしますね。

メモベースで学んだことの羅列を。

classコンポーネント

昔Javaをやってた頃の懐かしさを覚えますねw

stateはconstructor(props)で初期化。

Componentをextendsして、propsをsuperで継承。

class Counter extends Component {
  constructor(props) {
    super(props)
    this.state = { count: 0 }
  }
}

state

stateは直接さわれないので注意!、setState関数で上書きする。

handlePlusButton = () => {
  this.setState({count: this.state.count + 1})
}

ローカルステートはVueでいうdata()と同義と捉えています。

Redux

redux-thunkのやり方。

action, reducer, stateの3種が重要。

VuexのようにMutationやGetterはないみたい。

connect関数でstateとコンポーネントを紐付けることができる。

コンポーネント

import { connect } from 'react-redux'

const mapStateToProps = state => ({ events: state.events })
const mapDispatchToProps = ({ readEvents })
export default connect(mapStateToProps, mapDispatchToProps)(EventsIndex)

実装順序としては以下の順が良さそう。
1.Component
2.Action
3.Reducer

actionsで定義するdispatchメソッドで渡す引数は、Reducer内部で使用するため。

// action
dispatch({ type: READ_EVENTS, response })

// reducer
case READ_EVENTS:
return _.mapKeys(action.response.data, 'id')
// action
dispatch({ type: DELETE_EVENTS, id })

// reducer
case DELETE_EVENTS:
delete events[action.id]
return { ...events }

ReactRouterDOM

コンポーネントにLinkを、ルートのindex.jsに{ BrowserRouter, Router, Switch }をインポートする

components/events_index.js

<Link to="/events/new">New Event</Link>

ほぼnuxt-router, vue-routerと同義。

index.js

<BrowserRouter>
  <Switch>
    <Route path="/events/new" component={EventsNew}></Route>
    <Route path="/events/:id" component={EventsShow}></Route>
    <Route exact path="/" component={EventsIndex}></Route>
    <Route exact path="/events" component={EventsIndex}></Route>
  </Switch>
</BrowserRouter>

exactがつく場合はpathがURLと正確に一致したときにルーティングされる。/eventsのexactを取り除くと、/events/newでEventsNewコンポーネントだけでなく、EventsIndexコンポーネントも描画されてしまう。

pathとcomponentを紐付ける。上の場合、/ (ルート)にEventsIndexのコンポーネントを表示するようにする

可変の場合は:idのようにコロンをつける。nuxtのファイル名のように_id.jsとかにはならないので混同しないように注意。

Routeに都度足さなきゃいけないんだろうなぁ...Next.jsだとこの辺隠蔽してくれるんだろうか

ReduxForm

connect()関数の引数にreduxForm()関数をいれる

export default connect(mapStateToProps, mapDispatchToProps)(
  reduxForm({ validate, form: 'eventShowForm', enableReinitialize: true })(EventsShow)
)
renderField(field) {
  const { input, label, type, meta: { touched, error } } = field
  return (
    <TextField
      hintText={label}
      floatingLabelText={label}
      type={type}
      errorText={touched && error}
      {...input}
      fullWidth={true}
    />
  )
}

meta: { touched, error }はReduxForm特有のプロパティ

フォーム制御
const { pristine || submitting } = this.props
フォームに値がない場合、ボタン押下不可にする Redux-formが提供する関数

redux-devtools-extension

reduxのデバッグツール

index.js

import { composeWithDevTools } from ‘redux-devtools-extension'

const enhancer = process.env.NODE_ENV === 'development'
  ? composeWithDevTools(applyMiddleware(thunk))
  : applyMiddleware(thunk)
const store = createStore(reducer, enhancer)

MaterialUI

ReactのUIコンポーネント。Material UIとAnt Designのツートップみたい。

index.js

import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'

ReactDOM.render(
  <MuiThemeProvider>
    <Provider store={store}>
      <BrowserRouter>
        <Switch>
          <Route path="/events/new" component={EventsNew}></Route>
          <Route path="/events/:id" component={EventsShow}></Route>
          <Route exact path="/" component={EventsIndex}></Route>
          <Route exact path="/events" component={EventsIndex}></Route>
        </Switch>
      </BrowserRouter>
      </Provider>
    </MuiThemeProvider>
  ,
  document.getElementById('root')
);

大外をMuiThemeProviderで囲む。

各コンポーネント単位で読み込むUIコンポーネントをimportして使う。

例:components/event_index.js

import {
  Table,
  TableBody,
  TableHeader,
  TableHeaderColumn,
  TableRow,
  TableRowColumn
} from 'material-ui/Table'

まとめ

ひとまずUdemy講座を一通り視聴・実装をしてみました。

Vuexに比べてReduxは難易度が高く感じています。

今後hooksが盛んになってきて、Recoilがスタンダードになってくるのでしょうか?

ライブラリ選定などがReactの難しさを上げているのかもなと感じています。

React+Reduxでの開発力だけでなく、まずは広くHooksでの実装などにチャレンジしていき、現場で使う場合はそこでの技術をしっかりとキャッチアップしていきたいと思います。