核となるコンセプト

Redux自体はとてもシンプルです。

アプリの状態が、単なるオブジェクトで記述されているのを想像してください。例えば、ToDoアプリの状態がこうだとしたら:

{
  todos: [{
    text: 'ごはんを食べる',
    completed: true
  }, {
    text: 'エクササイズ',
    completed: false
  }],
  visibilityFilter: 'SHOW_COMPLETED'
}

このオブジェクトは、Setterがないことを除けばモデルのようです。Setterがないので、コードの異なる部分が状態を任意に変えるのは難しいです。そのため、バグを出しにくくなります。

状態の何かを変えるには、ActionをDispatch(送信)する必要があります。Actionは何が起きたか記述する、単なるJavaScriptのオブジェクトです(どんな魔法も紹介していないことに気づきましたか?)。 いくつかActionの例をあげましょう:

{ type: 'ADD_TODO', text: 'Go to swimming pool' }
{ type: 'TOGGLE_TODO', index: 1 }
{ type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' }

すべての変化に対して、Actionとして記述することを強制します。これにより、アプリで何が起きているかがはっきり分かります。つまりもし何か変化したら、なぜ変化したのか分かります。Actionは起きたことを伝える、パンくずのようなものです。 最後に、Reducerという関数を書きます。状態とActionを結びつけるためです。これも、決して魔法ではありません。ただの関数です。状態とActionを引数に取り、アプリの次の状態を返します。大きなアプリだと、このような関数を1つ書くのは難しいでしょう。そのため状態の一部を管理する、より小さな関数をいくつか書きます:

function visibilityFilter(state = 'SHOW_ALL', action) {
  if (action.type === 'SET_VISIBILITY_FILTER') {
    return action.filter
  } else {
    return state
  }
}

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

そして状態全体を管理するもう1つのReducerを書きます。このReducerは、それぞれ対応する状態のキーとともに、上記2つのReducerを呼び出します:

function todoApp(state = {}, action) {
  return {
    todos: todos(state.todos, action),
    visibilityFilter: visibilityFilter(state.visibilityFilter, action)
  }
}

これが基本となる、Reduxの全体的なアイデアです。ReduxのAPIはまったく使っていないことに注意してください。このパターンを容易にするためのユーティリティはいくつかあります。しかし主なアイデアは、Actionのオブジェクトに対し、どうやって状態を更新するか記述することです。そしてコードの90% は、ただふつうのJavaScriptです。Redux自体や、ReduxのAPI、またどんな魔法も使っていません。

results matching ""

    powered by

    No results matching ""