LoginSignup
22
17

More than 5 years have passed since last update.

Redux ExampleのTodo Listをはじめからていねいに(2)

Last updated at Posted at 2016-03-12

Reduxの公式ExampleにあるTodo Listを機能ごとに作っていくシリーズの2回目です。

1回目では、TodoをTodo Listに追加する「Add Todo」を作りました。
今回は、Todoの完了・未完了を切り替える「Toggle Todo」の機能を作っていきます。

1回目を読んでない人は、そちらを先にどうぞ。
Redux ExampleのTodo Listをはじめからていねいに(1)

1. 完了・未完了を表すcompletedによってスタイルを変える

todoにcompleted要素を追加して、とりあえず取り消し線を表示する

まず、todoごとに完了・未完了を区別するために、completedという要素を
加えます。前回つくったtodo reducerを修正します。
todo作成時は、未完了なので、デフォルトでfalseにしておきます。

デフォルトでfalseにするので、actionからなにか受け取る必要はありませんので、
addTodoのactionCreatorは変更ありません。

reducers/todos.js
const todo = (state, action) => {
  switch (action.type) {
    case 'ADD_TODO':
      return {
        id: action.id,
        text: action.text,
        completed: false
      }
    default:
      return state
  }
}

const todos = (state = [], action) => {
  // ...
}
export default todos

completedによってviewを変えるので、Todoコンポーネントを修正します。
completedがtrueだったらtextDecorationをline-throughにします。

components/Todo.js
const Todo = ({ completed, text }) => (
  <li style={{textDecoration: completed ? 'line-through' : 'none'}}>
    {text}
  </li>
)

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

これで、stateで保持されるtodoのcompletedがtrueのとき取り消し線がつきます。
動作確認は、一時的にreducers/todos.jsのcompleted: falseを
trueに変えてやればちゃんと取り消し線が付いているはずです。

actionCreatorからcompleted要素を操作する

次に、action経由で取り消し線のON/OFFを行うために、actionCreatorとreducerの作成を行います。
actionCreatorで必要なのは、todoのidだけです。

actions/index.js
export const addTodo = (text) => {
  // ...
}

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

reducerはtodosとtodoの両方にtoggleTodoのactionが呼び出されたときの処理が必要です。
storeにはtodos reducerが登録されており、todoはtodosが呼び出されているに過ぎません。

todos reducerでは、map関数を使って現在のtodosに格納されているすべてのtodoを
todo reducerに渡しています。
todo reducerでは、actionCreatorに渡したidと一致するtodoに対して、
completedだけを反転させています。
Object.assignで現在のstateと、completedを書き換えたstateを結合しています。

reducers/todos.js
const todo = (state, action) => {
  switch (action.type) {
    // ...
    case 'TOGGLE_TODO':
      if (state.id !== action.id) {
        return state
      }
      return Object.assign({}, state, {
        completed: !state.completed
      })
    // ...
  }
}

const todos = (state = [], action) => {
  switch (action.type) {
    // ...
    case 'TOGGLE_TODO':
      return state.map((t) =>
        todo(t, action)
      )
    // ...
  }
}
export default todos

index.jsからtoggleTodoを使ってみると、
正しく取り消し線が付いていると思います。

index.js
import { addTodo, toggleTodo } from './actions'

store.dispatch(addTodo('Hello React!'))
store.dispatch(toggleTodo(0))

2. クリックしてcompletedの値を変える

それでは、クリックしたときにcompletedの値を変更する処理を書いていきます。

stateをpropsとして使えるようにしたと同じように、dispatchをpropsとして
使えるようにします。

onTodoClickという名前でdispatchをstoreに格納します。
idを渡すと、dispatch(toggleTodo(id))のようにtoggleTodo actionCreatorで
actionをつくって、dispatchによりstoreのstateを変更します。
処理の流れは今までと同じです。

containers/VisibleTodoList.js
import { toggleTodo } from '../actions'
// ...
const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
  }
}

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

export default VisibleTodoList

TodoListコンテナでonTodoClickが使えるようになったので、Todoコンテナを
つくるところで、他のpropsと同じようにonTodoClick(todo.id)も渡します。

components/TodoList.js
const TodoList = ({ todos, onTodoClick }) => (
  <ul>
    {todos.map((todo) =>
      <Todo
        key={todo.id}
        {...todo}
        onClick={() => onTodoClick(todo.id)}
      />
    )}
  </ul>
)

TodoList.propTypes = {
  // ...
  onTodoClick: PropTypes.func.isRequired
}

export default TodoList

TodoコンテナでTodoListから渡されたonClickを使います。

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

Todo.propTypes = {
  onClick: PropTypes.func.isRequired,
  // ...
}

export default Todo

これでクリックするとcompletedの値が変更され、取り消し線がON/OFFされます。

Untitled.gif

「Toggle Todo」機能が完成しました。
ここまでのソースコードはGitHubにあげています。

続きます。。
次回、表示するTodo Listを完了または未完了のTodoだけにする「Filter Todo」機能を実装します。

2016/3/15 update
Redux ExampleのTodo Listをはじめからていねいに(3)を書きました。

22
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
17