React + ReduxでTodoアプリを作ってみよう！『Toggle Todo編』

#概要

前回の記事ではTodoアプリにTodoを追加する『Add Todo』機能を実装しました。今回は、追加されたTodoをクリックした際に斜線を引けるようにし、Todoの未・済を判別出来る機能を実装したいと思います！

前回の記事
[React + ReduxでTodoアプリを作ってみよう！『Add Todo編』](https://qiita.com/micropig3402/items/8e44bc042eda13b98c95)

#completed属性を付与する
completed属性を付与することで、Todoが完了済みなのか未完了なのかを判別できるようにしましょう！Todoを追加する際にcompleted属性にfalseをデフォルトとして設定します！

```react:src/reducers/todos.js
import {ADD_TODO, TOGGLE_TODO} from '../actions';

const todos = (state = [], action) => {
  switch (action.type) {
    case ADD_TODO:
      return [...state, {id: action.id, text: action.text, completed: false}];
    default:
      return state;
  }
};

export default todos;
```

#completed属性によってTodoのstyleを変更する
completedの属性がtrueかfalseかによってTodoに斜線を引けるようにstyleを反映させましょう！

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

const Todo = ({onClick, completed, text}) => {
  return (
    <li style={{textDecoration: completed ? 'line-through' : 'none'}}>
      {text}
    </li>
  );
};

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

export default Todo;
```

#Action経由でcompleted属性を操作する
Action経由でcompleted属性を操作するために、まずはAction Creatorを作成しましょう。横線を引くTodoを判別するために、idを取得します。

```react:src/actions/index.js
export const ADD_TODO = 'ADD_TODO';
export const TOGGLE_TODO = 'TOGGLE_TODO';

let nextTodoId = 0;
export const addTodo = text => {
  return {
    type: ADD_TODO,
    id: nextTodoId++,
    text,
    //text: text,
  };
};

export const toggleTodo = id => {
  return {
    type: TOGGLE_TODO,
    id,   
    //id: id
  };
};
```

またreducersに戻り`action.type`が`TOGGLE_TODO`の際の状態遷移の方法を記述しましょう。この中では、stateに保管されているTodoのidと横線を引きたいTodoのidを比較し、お互いに一致するようであれば、一致したidのTodoが持っているcompleted属性を逆転させます。

```react:src/reducers/todo.js
import {ADD_TODO, TOGGLE_TODO} from '../actions';

const todos = (state = [], action) => {
  switch (action.type) {
    case ADD_TODO:
      return [...state, {id: action.id, text: action.text, completed: false}];
    case TOGGLE_TODO:
      return state.map(todo =>
        todo.id === action.id ? {...todo, completed: !todo.completed} : todo
      );
    default:
      return state;
  }
};

export default todos;
```

#Todoをクリックしてcompleted属性を変更する
まずは、`mapDispatchToProps`を作成してdispatchを
propsとして使えるようにしましょう。toggleTodoという名前でdispatchをstoreに格納します。

```react:src/containers/VisibleTodoList.js
import {connect} from 'react-redux';
import TodoList from '../components/TodoList';
import {toggleTodo} from '../actions';
const mapStateToPorops = state => {
  return {todos: state.todos};
};

const mapDispatchToProps = dispatch => {
  return {
    toggleTodo: id => {
      dispatch(toggleTodo(id));
    },
  };
};

const VisibleTodoList = connect(
  mapStateToPorops,
  mapDispatchToProps
)(TodoList);

export default VisibleTodoList;
```

これでTodoListでtoggleTodoが使えるようになったので、TodoコンポーネントのonClick属性にtodoのidを引数としてtoggleTodoを渡します。

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

const TodoList = ({todos, toggleTodo}) => {
  return (
    <ul>
      {todos.map(todo => (
        <Todo key={todo.id} {...todo} onClick={() => toggleTodo(todo.id)} />
      ))}
    </ul>
  );

  TodoList.propTypes = {
    todos: PropTypes.arrayOF(
      PropTypes.shape({
        id: PropTypes.number.isRequired,
        text: PropTypes.string.isRequired,
      }).isRequired
    ).isRequired,
  };
};

export default TodoList;
```

Todoコンポーネント内でpropsとして渡されたtoggleTodoをonClick属性に付与します。

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

const Todo = ({onClick, completed, text}) => {
  return (
    <li
      onClick={onClick}
      style={{textDecoration: completed ? 'line-through' : 'none'}}>
      {text}
    </li>
  );
};

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

export default Todo;
```

以上でTodoをクリックした際に取り消し線を引く機能を実装できました！

![ezgif.com-optimize (2).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/343290/89d4d9af-50b2-e078-111d-ee887ea36032.gif)

次回は表示するTodoを完了・未完了によって分ける「Filter Todo」機能を実装したいと思います。

#リファレンス
- [Redux Basic Tutrial](https://redux.js.org/basics/basic-tutorial)
- [Redux ExampleのTodo Listをはじめからていねいに(2)](https://qiita.com/xkumiyu/items/e7e1e8ed6a5d6a6e20dd)
- [CSSリファレンス
text-decoration](http://www.htmq.com/css/text-decoration.shtml)