#概要
前回までの記事では、ReactとReduxの基本をまとめさせて頂きました。今回からは、さらにもう一歩踏み込んでReactとReduxを用いたTodoアプリを作ってみたいと思います。(参考:Redux Basic Tutrial)
前回の記事
『Redux』を用いて状態管理をしてみよう!
今回は、TodoをTodoListに追加する__『Add Todo』__の機能を実装したいと思います。
#Action & Action Creator
まずは、ActionとAction Creatorの定義から始めていきましょう!
ActionのtypeはADD_TODO
と定義し、text
は入力されたTodo、id
は追加されていくTodoの番号となります。
export const ADD_TODO = 'ADD_TODO';
let nextTodoId = 0;
export const addTodo = text => {
return {
type: ADD_TODO,
id: nextTodoId++,
text, //text: textを省略
};
};
#Reducer
次にReducerを定義していきましょう!
まずは全てのReducerを結合するファイルであるsrc/reducers/index.js
を作成しましょう!combineReducers()
などに関して知りたい方は前回の記事をご覧ください
import {combineReducers} from 'redux';
import todos from './todo';
const todoApp = combineReducers({todos});
export default todoApp;
続いて、実際にActionから発行されるtypeを受け取って状態遷移を行うsrc/reducers/todo.js
を書いていきましょう!
...state
によって今まで追加されてきたTodoが、{id: action.id, text: action.text}
によって新しく追加されたTodoが配列に格納され返ってきます。
import {ADD_TODO} from '../actions';
const todos = (state = [], action) => {
switch (action.type) {
case ADD_TODO:
return [...state, {id: action.id, text: action.text}];
default:
return state;
}
};
export default todos;
#store
storeはアプリケーション内のstate(状態)を管理しているところです。詳しくは先ほどと同様に前回の記事を参照してください。
import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux';
import {createStore} from 'redux';
import App from './components/App';
import {addTodo} from './actions';
import * as serviceWorker from './serviceWorker';
import reducers from './reducers';
let store = createStore(reducers);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
#Presentational Components
『Presentational Components』はpropsとして受け取ったデータを表示することに専念するコンポーネントになります。
src/components/Todo.js
ではpropsとして受け取ったデータを表示します。
import React from 'react';
import PropTypes from 'prop-types';
const Todo = ({text}) => {
return <li>{text}</li>;
};
Todo.propTypes = {
text: PropTypes.string.isRequired,
};
export default Todo;
一方src/components/TodoList.js
では、map
を用いてpropsとして受け取ったtodos
をTodo Componentに渡しています。{...todo}
はtodoの全ての要素を表しており、id={todo.id}
、text=todo.text
と同じ意味を持っています。
import React from 'react';
import propTypes from 'prop-types';
import Todo from './Todo';
const TodoList = ({todos}) => {
return (
<ul>
{todos.map(todo => (
<Todo key={todo.id} {...todo} />
))}
</ul>
);
TodoList.propTypes = {
todos: propTypes.arrayOF(
propTypes.shape({
id: propTypes.number.isRequired,
text: propTypes.string.isRequired,
}).isRequired
).isRequired,
};
};
export default TodoList;
#Container Components
Container componentはPresentational componentに具体的なデータやコールバック関数を与えるコンポーネントです。
src/containers/VisibleTodoList.js
では、まずはmapStateToPorops
を用いてstateから必要な情報をpropsとしてマッピングさせます。そしてconnect関数を用いてTodoList Componentとstateを結びつけて、VisibleTodoList
としてexportします。
import {connect} from 'react-redux';
import TodoList from '../components/TodoList';
const mapStateToPorops = state => {
return {todos: state.todos};
};
const VisibleTodoList = connect(mapStateToPorops)(TodoList);
export default VisibleTodoList;
これで、ブラウザにTodoを表示させることが出来るようになりましたが、まだTodoを入力するFormがないので作成していきます。
import React from 'react';
import {connect} from 'react-redux';
import {addTodo} from '../actions';
let AddTodo = ({dispatch}) => {
let input;
return (
<div>
<input
ref={node => {
input = node;
}}
/>
<button
onClick={() => {
dispatch(addTodo(input.value));
input.value = '';
}}>
Add Todo
</button>
</div>
);
};
AddTodo = connect()(AddTodo);
export default AddTodo;
src/containers/AddTodo.js
ではdispatch(addTodo(input.value));
と書くことで、buttonを押した際にinput要素に入力された内容をTodoに追加出来るようになっています。
またinput要素内でrefを用いておりますが、refを用いることで、あらかじめ宣言していたinput
に入力された内容を格納することができます。今回は以下に示す3つの方法の中でrefコールバック属性を用いる方法を選択しています。
Refsを扱うには3つ方法があります。
- React.createRefメソッドを用いる(v16.3.0以上で利用可能)
- refコールバック属性を用いる
- ref文字列属性を用いる(非推奨 v17で削除)
#ブラウザに表示させてみよう!
では、src/components/App.js
に<AddTodo />
と<VisibleTodoList />
を追加してブラウザに表示させてみましょう!
import React from 'react';
import VisibleTodoList from '../containers/VisibleTodoList';
import AddTodo from '../containers/AddTodo';
const App = () => {
return (
<div className="App">
<AddTodo />
<VisibleTodoList />
</div>
);
};
export default App;
これで『Add Todo』の機能は実装できたと思います。次回は、Todoの完了・未完了を切り替える『Toggle Todo』の機能を実装していきましょう!
#リファレンス