ミドルウェアを使わないreduxをちゃんと理解するための個人メモ

仕事でいきなりredux/redux-saga さらに redux-actions の環境を触ってきて

ミドルウェアを使わないシンプルな構成のreduxの理解が浅かったのでちゃんと覚えようと思った

環境構築

お手軽 create-react-app

github.com

$ create-react-app react-redux-example

次にreduxを使うのに必要なnpmモジュールをインストールする

$ yarn add redux react-redux

react-reduxreactredux を扱うために必要

これだけで環境は整った

処理の流れ

ActionType

ただの変数

イベントの名前を付けてく

const ADD_ITEM = 'ADD_ITEM'
const DELETE_ITEM = 'DELETE_ITEM'

Action

オブジェクトを返すだけのピュアな関数

typeを設定するのはお約束

// typeにActionTypeを設定
export const addItem = item => ({ type: ADD_ITEM, item })
export const deleteItem = id => ({ type: DELETE_ITEM, id })

// addItem('hello')
// -> { type: 'ADD_ITEM', item: 'hello' }

Reducer

storeの構造はここで決まる

import { combineReducers } from 'redux'

// 初期値
const initialState = [
  {
    item: 'hello'
  }
]

const todos = (state = initialState, action) => {
  switch (action.type) {

    // アイテムを追加
    case ADD_ITEM:
      return [...state, { item: action.item }]

    // アイテムを削除
    case DELETE_ITEM:
      return state.filter((v, k) => k !== action.id)

    default:
      return state
  }
}

// 分割されたreducerを合成
// これがstore全体の構造になる
const reducer = combineReducers({
  todos
})

Storeを生成

import { createStore } from 'redux'

// 前述のReducersで生成した値が入る
const store = createStore(reducer)

ミドルウェアがある場合はcreateStoreの第2引数に設定を渡すが

今回は素のredux構成なので省略

描画する

index.js を編集

import { Provider } from 'react-redux'
// ...

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

// ...

ここでやっとreact-reduxが登場

に生成したstoreを渡すと

storeの値やActionが使えるようになる

App.js

containerとなるものは全てこの形式で書かれる

import { connect } from 'react-redux'

class App extends Component<{}> {
  render() {
    const { todos, actions } = this.props
    return (
      <div>
        <button onClick={() => actions.addItem('world')}>ADD</button>
        <ul>
          {todos.map((v, k) => <li onClick={() => actions.deleteItem(k)}>{v.item}</li>)}
        </ul>
      </div>
    )
  }
}

// stateにstoreの値が入ってる
// this.props.todosで使えるようになる
const mapStateToProps = state => ({
  todos: state.todos
})

// Actionsで定義した関数が使えるようになる
// this.props.actions.addItem('hello')
const mapDispatchToProps = dispatch => ({
  actions: bindActionCreators(Actions, dispatch)
})

// Appコンポーネントに各値を接続
export default connect(mapStateToProps, mapDispatchToProps)(App)

f:id:rskull:20171122012742g:plain

まとめ

処理の流れが分かってスッキリした

今回のソース

わかりやすいように出来るだけ1ファイルに納めて書いてる

github.com

次はミドルウェアを導入してどう変わっていくかを確かめる

※追記

タイトル変えました

以上