Reduxの理論編に引き続き実装編について説明していきます。
ではコードをもとに説明をしていきます。
今回は簡単なTODOアプリでTODOの追加・削除のみできるものを想定しています。
Reducer
まずは「Reducer」についてですが、理論編で説明したように「Reducer」は渡されてきた「Action」と現在の状態から新しい「State」を作成し返しています。
→「純粋関数」で副作用もないですね
import { combineReducers } from 'redux';
export function todoReducers(state={
list: []
}, action) {
switch (action.type) {
case "ADD_TODO":
return Object.assign({}, state, {
list: state.list.concat(action.todo)
});
case "REMOVE_TODO":
return Object.assign({}, state, {
list: state.filter(todo => {
return action.todo != todo;
})
});
default:
return state;
}
};
export default combineReducers({todoReducers});
Action
次にActionですが、これはReducerに渡す情報を返すだけの処理になっています。
TODOを追加する処理と、削除する処理があるのでそれぞれのActionを作成しています。
export function addTodo(todo) {
return {
type: "ADD_TODO",
todo
}
}
export function removeTodo(todo) {
return {
type: "REMOVE_TODO",
todo
}
}
Store
これに関しては、Storeを作成しているだけですね
import { createStore } from 'redux';
import reducers from './reducers';
const store = createStore(reducers);
export default store;
Entry部分
index.jsについては最初のEntryの部分で、コンポーネントの一番親と言っていい部分です。
またProviderとありますが、Providerはpropsで子コンポーネントに渡さずとも、コンポーネントツリー内でデータを渡すことができるものとなっています。
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import App from './App';
import registerServiceWorker from './registerServiceWorkder';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
,document.getElementById('root')
);
registerServiceWorker();
App(実際のTODOアプリメイン処理)
先ほど、providerをindex.jsで使用しているので、mapStateToPropsのようなfunctionを作成しStoreの中身をバケツリレーでなくとも受け取ることができます。
追加処理については、テキストボックスの中身に変更が加わると、このコンポーネント(App)内の「State」にセットします。そして、追加ボタンを押すとその「State」を「Action」に詰めて「Dispatch」します。
削除処理についても「Action」に詰めて「Dispatch」するところは同様で、「Store」内の「State」のTODOリストでループして、各TODOを「Action」に詰めて「Dispatch」しています。
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { addToDo, removeToDo } from './actions';
import store from './store';
class App extends Component {
constructor() {
super();
this.state = {
input: ""
};
}
render() {
<div>
<ul>
{this.props.todos.map(todo => {
return (
<li key={todo}>
<span>{todo}</span>
<button onClick={() => {this.props.dispatch(removeToDo(todo))}}>削除</button>
</li>
);
})}
</ul>
<input type="text" onChange={e => this.setState({input: e.target.value})} />
<button onClick={() => this.props.dispatch(addToDo(this.state.input))}>追加</button>
</div>
}
}
const mapStateToProps = state => {
return {
todos: state.todos.list
}
};
export default connect(mapStateToProps)(App);
まとめ
思ったより難しくなかったですよね。
ただ、ReducerやStateの数が増えたりすると、そのたくさんあるReducer・Stateをどう分割していくかが難しかったりします。
この記事を参考にReduxの知識をつけてもらえますと幸いです。