JavaScript
React
redux

ReduxのサンプルのTodoリストを真似てみる。Part.2

More than 1 year has passed since last update.

ReduxのサンプルのTodoリストを真似てみる。Part.1の続きです。


0.留意点



  • Redux ExampleのTodo Listをはじめからていねいに(1)を参考にさせて頂いて、Reduxのコードを書いた。

  • 初心者の覚書です。

  • 自分の環境で動くように参考にしたコードを適当に修正している。

  • Windows10 64bit , PowerShellなどで動かしている。

  • 見栄えを若干よくする為にbootstrap4を利用している。
    #1.Todoの配列でTodoリストを作る


reducersを修正

todoをtodosに変更 stateをtodoの配列にする

ファイル名を reducers/index.jsからreducers/todos.js に変更


reducers/todos.js

const todos = (state=[], action) => {

switch (action.type) {
case 'ADD_TODO':
return {
...state,
id: action.id,
text: action.text
}

default:
return state;
}
}
export default todos;


actions/index.jsはあたらしく作り直す。

combineReducers関数を使って、複数のreducers(複数のロジック)をまとめて扱えるようにする。

たとえば、

reducers/hoge.js のなかで、export default hoge

reducers/fuga.js のなかで、export default fuga

し、actions/index.jsで、importして

combineReducers({todos, hoge, fuga})

としておくと、stateオブジェクトのtodosプロパティ、hogeプロパティ、fugaプロパティとしてアクセスできる。この時点ではtodosだけだが、先のことを考えて準備しておく。


reducers/index.js

import todos from './todo'

import { combineReducers } from 'redux';

const todoApp = combineReducers({todos});
export default todoApp;



コンポーネントをつくる

この辺から、bootstrapを使う。クラス名の指定でできるだけ対応。React、Reduxは関係しない。

コンポーネントの前にまず、ルートのhtmlファイルを修正


index.html

<!DOCTYPE html>

<html>
<head>
<meta charset="UTF-8">
<title>React,ReduxでTodoリストを作ろう</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
</head>
<body >
<!-- classでBootsrapに関する設定 -->
<div class="mx-auto w-50 mt-3" id="root"></div>

<script src="dist/index.js"></script>
</body>
</html>


Todo一つ一つに対応するTodoコンポーネント


components\Todo.js

import React from 'react';

import PropTypes from 'prop-types';

//classNameでBootsrapに関する設定
const Todo = ({text})=>(
<li className="list-group-item">{text}</li>
)

Todo.propTypes ={
text:PropTypes.string.isRequired
}

export default Todo;


複数のTodoコンポーネントを格納するTodoListコンポーネント


components\TodoList.js

import React from 'react';

import PropTypes from 'prop-types';
import Todo from './Todo';

//classNameでBootsrapに関する設定
const TodoList = ({todos})=>(
<ul className="list-group mx-auto p-3 bg-info rounded" style={{maxWidth:'36rem'}}>
{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



コンテナでstateとコンポーネントを結びつける

VisibleTodoListコンテナのなかで、state.todosを TodoListのpropsに関連付ける。

そのために、React-Reduxのconnect関数を使う。


containers\VisibleTodoList.js

import React from 'react';

import { connect } from 'react-redux';
import TodoList from '../components/TodoList'

function mapStateToProps(state){
return {
todos:state.todos
}
}

const VisibleTodoList = connect(mapStateToProps)(TodoList);
export default VisibleTodoList;



Appコンポーネントを修正

Appコンポーネントでは、上記のVisibleTodoListコンテナを読み込む。


components\App.js

import React from 'react';

import VisibleTodoList from '../containers/VisibleTodoList'

//classNameでBootsrapに関する設定
const App = () => (
<div>
<h1 className="text-center alert alert-info ">Todoリスト</h1>
<VisibleTodoList />
</div>
)

export default App;



エントリーポイントのindex.jsを修正

ここまでの変更に合わせて、import関係、モジュール参照名などを修正。


index.js

import React from 'react';

import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import todoApp from './reducers'
import { createStore } from 'redux';
import App from './components/App'
import addTodo from './actions'

let store = createStore(todoApp);
store.dispatch(addTodo('Todo 1番目'));
store.dispatch(addTodo('Todo 2番目'));
store.dispatch(addTodo('Todo 3番目'));
store.dispatch(addTodo('Todo 4番目'));
store.dispatch(addTodo('Todo 5番目'));

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



コマンド実行

npm run build

npm run start

http://localhost:8080で動作確認

2018_0528_1351_34.jpg

ソースコード 03


2.Todoの新規追加のフォームをつくる

初めの読み込み時に、input変数にDOMへの参照が格納される。

AddTodo コンポーネントにdispatchを引数で渡す。

新規追加ボタンをクリックすると、コールバックで、ユーザー入力のテキストを用いたactionを引数にしてdispatch関数を実行。


containers\AddTodo.js

import React from 'react';

import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import addTodo from '../actions/index.js';

let AddTodo = ({ dispatch }) => {
let input;
//className,htmlForなどはbootstrapのため
return (
<div className="form-group">
<label htmlFor="todo_name">Todoの名称</label>
<input type="text" className="form-control" id="todo_name" placeholder="Todoの名称" ref={(node) => { input = node }} />
<button className="btn btn-primary btn-lg btn-block mt-1" onClick={() => { dispatch(addTodo(input.value)); input.value="" }}>新規追加</button>
</div>
)
}
AddTodo = connect()(AddTodo);
export default AddTodo;



Appコンポーネントを修正


components\App.js

import React from 'react';

import VisibleTodoList from '../containers/VisibleTodoList'
import AddTodo from '../containers/AddTodo'

//classNameでBootsrapに関する設定
const App = () => (
<div>
<h1 className="text-center alert alert-info ">Todoリスト</h1>
<VisibleTodoList />
<AddTodo />
</div>
)

export default App;



実行結果

2018_0528_1531_46.jpg

ソースコード 04