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

[ReduxのサンプルのTodoリストを真似てみる。Part.2](https://qiita.com/tkarasuma/items/2a3dc7a0bca1f0503f79)の続きです。

#0.留意点
- [Redux ExampleのTodo Listをはじめからていねいに(2)](https://qiita.com/xkumiyu/items/e7e1e8ed6a5d6a6e20dd)を参考にさせて頂いて、Reduxのコードを書いた。
- 初心者の覚書です。
- 自分の環境で動くように参考にしたコードを適当に修正している。
- Windows10 64bit , PowerShellなどで動かしている。
- 見栄えを若干よくする為にbootstrap4を利用している。

#1.Todoに進行中/完了のcompleted属性を付ける

##Todoコンポーネントの修正

Todoコンポーネントに渡されてcompletedに応じて、liタグのクラスを変える。

```jsx:components\Todo.js

import React from 'react';
import PropTypes from 'prop-types';

//classNameでBootsrapに関する設定
const Todo = ({text,completed})=>(
    <li className={completed?"list-group-item bg-secondary text-dark":"list-group-item"}>{text}</li>
)

Todo.propTypes ={
    text:PropTypes.string.isRequired,
    completed:PropTypes.bool.isRequired
}
export default Todo;

```
あわせて、TodoListコンポーネントもpropTypesのところを修正

```jsx: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,
      completed:PropTypes.bool.isRequired
    }).isRequired).isRequired
  }
  
export default TodoList

```

##ActionCreator関数を修正

Todoのcompletedを反転させるToggleTodoアクションをつくる。

また、export default は１ファイルに複数使えないようなので、export constに変更。それに応じて、
containers\AddTodo.js で　import {addTodo} from '../actions/index.js';　に修正
index.js で、import {addTodo,toggleTodo} from './actions'　に修正しておく。


```javascript:actions\index.js
let nextTodoId=0
export const addTodo= (text)=>{
    return{
        type:'ADD_TODO',
        id:nextTodoId++,
        text

    }
}

export const toggleTodo=(id)=>{
    return{
        type:'TOGGLE_TODO',
        id
    }
}

```

#reducers関数を修正

TOGGLE_TODO アクションに対応させる。

```javascript:reducers\todo.js
const todos = (state = [], action) => {
    switch (action.type) {
        case 'ADD_TODO':
            return [...state,
            {
                id: action.id,
                text: action.text,
                completed: false
            }
            ]
        case 'TOGGLE_TODO':
            state.map(
                (todo) => {
                    if (action.id !== todo.id) {
                        return todo;
                    } else {
                        return  Object.assign(todo,{completed:!todo.completed});
                    }
                }
            );
        default:
            return state;
    }
}
export default todos;
```

##index.jsを修正

ためしに、ひとつ、TOGGLE_TODO アクションをdispatchしてみる。

```jsx: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,toggleTodo} 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番目'));
store.dispatch(toggleTodo(2));


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

```
##実行結果

![2018_0529_1305_07.jpg](https://qiita-image-store.s3.amazonaws.com/0/76757/a9704ff5-1d70-9953-8c6b-6fd9b74d8291.jpeg)

[ソースコード 05](https://github.com/tkarasuma/JavaScript/tree/master/ws_05)

#2.Todoにクリックイベントをつける

Todoをクリックすると、completedを反転できるようにする。

階層の上の方のVisibleTodoListコンテナから。dispatchを下層コンポーネントでpropsとして使えるように、onTodoClickを渡す。onTodoClickには id引数 と toggleTodoアクション作成関数　を用いてdispatchを実行できる関数が入っている。

```javascript:VisibleTodoList.js
import React from 'react';
import { connect } from 'react-redux';
import TodoList from '../components/TodoList'
import {toggleTodo} from '../actions'


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

function mapDispatchToProps(dispatch){
    return {
        onTodoClick:(id)=>{dispatch(toggleTodo(id))}
    }
}

const VisibleTodoList = connect(mapStateToProps,mapDispatchToProps)(TodoList);
export default VisibleTodoList;
```
その下のTodoListコンポーネントでは、
()=>onTodoClick(todo.id)　
をOnClickプロパティとしてTodoにわたす。ここで個々のTodoのidと結び付けられている。

```jsx:components\TodoList.js
import React from 'react';
import PropTypes from 'prop-types';
import Todo from './Todo';

//classNameでBootsrapに関する設定
const TodoList = ({todos,onTodoClick})=>(
    <ul className="list-group mx-auto p-3 bg-info rounded" style={{maxWidth:'36rem'}}>
    {todos.map(
        (todo)=>(<Todo key={todo.id} {...todo} onClick={()=>onTodoClick(todo.id)}/>)
    )}
    </ul>
)

TodoList.propTypes = {
    todos: PropTypes.arrayOf(PropTypes.shape({
      id: PropTypes.number.isRequired,
      text: PropTypes.string.isRequired,
      completed:PropTypes.bool.isRequired
    }).isRequired).isRequired,
    onTodoClick:PropTypes.func.isRequired
  }
  
export default TodoList

```

最下層のTodoコンポーネントで、onClickプロップスとして渡された関数をクリック時のイベントハンドラとして登録している。

```jsx:components\Todo.js

import React from 'react';
import PropTypes from 'prop-types';

//classNameでBootsrapに関する設定
const Todo = ({text,completed,onClick})=>(
    <li className={completed?"list-group-item bg-secondary text-dark":"list-group-item"} onClick={onClick}>{text}</li>
)

Todo.propTypes ={
    text:PropTypes.string.isRequired,
    completed:PropTypes.bool.isRequired,
    onClick:PropTypes.func.isRequired
}

export default Todo;

```
##実行結果

![6t1mo-4fufx.gif](https://qiita-image-store.s3.amazonaws.com/0/76757/713ba48e-392c-d90b-bae1-f40b69da04d3.gif)

[ソースコード 06](https://github.com/tkarasuma/JavaScript/tree/master/ws_06)