サイトアイコン 上尾市のWEBプログラマーによるブログ

「React + Redux入門」の感想・備忘録

kindle本「React + Redux入門」のまとめ。

点数

82点

感想

とてもわかりやすかった。

特にreact-reduxの説明が段階的になっていて、なぜそのようになるかを理解することができた。

Reduxの仕組み

状態をStoreと呼ばれるJavaScriptオブジェクト(データだけでなくメソッドも持っている)で管理する。

Storeの変更は事前に定義されたActionと呼ばれるJavaScriptオブジェクトをReducerと呼ばれる関数に渡す(Storeのdispatchメソッドをコール)必要がある。

なぜReactと相性が良いのか

Reactでは各コンポーネントがstateを保持しているため、コンポーネントが増えるとstateも増える。

すると、stateの依存関係が複雑になり、stateを変更するためのメソッドをどこに定義するかも問題になる。

Reduxを使うと、これらを1箇所で管理できるようになる。

状態の変更

StoreのdispatchメソッドにActionオブジェクトを渡すと、Reducer関数が実行され、新しいStoreオブジェクトが返却される。

Reduxの導入

ReactアプリにReduxを追加する

  1. yarn add create-react-app
  2. npx create-react-app app
  3. cd app; yarn add redux react-redux
  4. touch src/reducers.js
import { combineReducers } from 'redux';

export function todos(state = {
  list: []
}, action) {
  switch (action.type) {
    case "ADD_TO_DO":
      state.list = state.list.concat(action.todo);
      return Object.assign({}, state);
    case "REMOVE_TO_DO":
      state.list = state.list.filter(todo => {
        return (action.todo != todo);
      });
      return Object.assign({}, state);
    default:
      return state;
  }
}
export default combineReducers({
  todos
});

combineReducers

2つ以上の状態を管理したい場合、Reducerを複数作成し、combineReducers関数に渡す。

ReactのmapStateToPropsではstate.nameがstate.Reducer名.nameのように1階層増えるので注意。

https://qiita.com/usagi-f/items/ae568fb64c2eac882d05

  1. touch src/actions.js
export function addToDo(todo) {
  return {
    type: 'ADD_TO_DO',
    todo
  }
}
export function removeToDo(todo) {
  return {
    type: 'REMOVE_TO_DO',
    todo
  }
}
  1. touch src/store.js
import { createStore } from 'redux';
import reducers from './reducers';

const store = createStore(reducers);
export default store;

※ Storeは別ファイルにすることが多い。

ここまででReduxの準備は完了。
Reactには触れていない点に注目。

react-reduxを追加する

index.js

react-reduxのProviderコンポーネントのstore属性を使うと、子コンポーネントからStoreにアクセスできるようになる。

import { Provider } from "react-redux";
import store from './store';
// 〜省略〜
<Provider store={store}>
  <App />
</Provider>,

App.js

react-reduxのconnext関数を使うと、コンポーネントからStoreにアクセスできるようになる。

import { connect } from "react-redux";
// 〜省略〜
export default connect()(App);

ただし、これだけでは個別のデータにアクセスすることはできない。
propsにStoreを反映させるには、mapStateToProps関数を定義してconnect関数に渡す必要がある。
mapStateToPropsは引数に現在のStoreが渡される。

const mapStateToProps = state => {
  return {
    todos: state.todos.list // combineReducersを使っているのでtodosが間に入る
  }
};
export default connect(mapStateToProps)(App);

さらに、Storeの変更をできるようにするには、ActionをReducerに渡す必要がある。
実はProviderの子要素でconnect()したコンポーネントは、this.props.dispatchでStoreのdispatchメソッドをコールすることができる。

import { addToDo, removeToDo } from './actions';
// 〜省略〜
<button onClick={() => this.props.dispatch(addTodo(this.state.input))}>追加</button>

this.props.dispatchは冗長な記述になってしまうので、mapDispatchToPropsという関数を定義するのが一般的。
mapDispatchToPropsは引数にdispatch関数が渡される。

const mapDispatchToProps = dispatch => {
  return {
    onAddToDo(todo) {
      dispatch(addToDo(todo))
    },
    onRemoveToDo(todo) {
      dispatch(removeToDo(todo))
    }
  }
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
モバイルバージョンを終了