BETA

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

投稿日:2018-10-28
最終更新:2018-10-28
※この記事は外部サイト(https://qiita.com/drafts/e7e1e8ed6a5d6a6e20dd)からのクロス投稿です

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は変更ありません。

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にします。

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だけです。

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を結合しています。

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を使ってみると、 正しく取り消し線が付いていると思います。

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を変更します。 処理の流れは今までと同じです。

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)も渡します。

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を使います。

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されます。

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

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

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

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

@xkumiyuの技術ブログ

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう
目次をみる
技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
or 外部アカウントではじめる
10秒で技術ブログが作れます!