Redux Basics (2): Reducers 翻訳

# **はじめに**
- [Redux Basics (1): Actions 翻訳](http://qiita.com/uramonk/items/28316e20ad6fb7968993)
- [Redux Basics (2): Reducers 翻訳](http://qiita.com/uramonk/items/3bce34db8cfd0587a63b)
- [Redux Basics (3): Store 翻訳](http://qiita.com/uramonk/items/a6cfa3fa7f7c6827c2b1)
- [Redux Basics (4): Data Flow 翻訳](http://qiita.com/uramonk/items/2e8d89ba0829fe657025)
- [Redux Basics (5): Usage with React 翻訳](http://qiita.com/uramonk/items/b4712620690711466b07)

ReduxのBasicsの翻訳の続きです。今回はReducersの翻訳となります。翻訳で間違いがあると思いますがそこはご了承ください。

翻訳は下記ページの10/31時点のものとなります。
http://redux.js.org/docs/basics/Reducers.html

_翻訳ここから_

# **Reducers**
[Actions](http://redux.js.org/docs/basics/Actions.html)では何かが起こった事実を述べましたが、どのようにアプリケーションの状態が応答で変化するかを具体的に述べていません。これはReducerの仕事です。

## **状態のかたちを設計する**
Reduxでは、すべてのアプリケーションの状態は一つのオブジェクトで保存されます。どんなコードを書く前にもその形を考えることは良いアイデアです。一つのオブジェクトとしてあなたのアプリの状態を最小に表現するのは何でしょうか？

Todoアプリのために、我々は２つの異なるものを保存したいです。

- 現在選択されたvisibility filter
- 実際のTodoのリスト

状態ツリーの中で、あるUIの状態と同じように、あるデータを保存する必要があることにしばしば気づきます。これはすばらしいことですが、UIの状態からデータを分割し続けることを試みましょう。

```js
{
  visibilityFilter: 'SHOW_ALL',
  todos: [
    {
      text: 'Consider using Redux',
      completed: true,
    },
    {
      text: 'Keep all state in a single tree',
      completed: false
    }
  ]
}
```

> **関係の注記**
> 多くの複雑なアプリでは、お互いの参照のために異なる実体を欲します。我々は、ネストすることなしに、できるかぎり標準化された状態を保ち続けるよう提案します。IDをkeyとして保存されたオブジェクトの全ての実体を保ち続け、他の実体やリストから参照するためにIDを使いましょう。アプリの状態をデータベースとして考えましょう。この手法は詳細に[normalizr](https://github.com/paularmstrong/normalizr)のドキュメントのなかで説明されています。例えば、状態のなかの`todosById: { id -> todo }`と`todos: array<id>`を保ちつづけることは、現実のアプリでは良いアイデアであり、我々は例をシンプルに保ち続けます。

## **Actionを取り扱う**
我々の状態オブジェクトが何のように見えるかを決定した今、我々はReducerを書く準備ができます。Reducerは前の状態をActionを取り、次の状態を返す単純な関数です。

```js
(previousState, action) => newState
```

[Array.prototype.reduce(reducer, ?initialValue)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce)へ渡す関数の種類のためReducerを呼び出します。Reducerが単純であることは大変重要です。Reducerの内部で**決して**すべきではならないことはこちらです:

- 引数を変化させる
- APIを呼び出したりルーティング遷移のような副作用を行う
- `Date.new()`や`Math.dandom()`のような単純でない関数を呼び出す

我々は[advanced walkthrough](http://redux.js.org/docs/advanced/)のなかでどのように副作用を実行するかを探索しています。今は、ただReducerは単純でなければならないことを覚えてください。**同じ引数が与えられ、次の状態が計算され返されるべきです。驚きはないです。副作用はないです。API呼び出しはないです。変化はないです。ただの計算です。**

これはおいておき、我々が早期に定義した[Action](http://redux.js.org/docs/basics/Actions.html)を理解するために、徐々に教えることでReducerを書き始めましょう。

特定の初期状態で初められます。Reduxは最初に`undefined(未定義)`な状態でReducerを呼び出します。これは我々のアプリの中で初期状態を返すチャンスです:

```js
import { VisibilityFilters } from './actions'

const initialState = {
  visibilityFilter: VisibilityFilters.SHOW_ALL,
  todos: []
}

function todoApp(state, action) {
  if (typeof state === 'undefined') {
    return initialState
  }

  // For now, don't handle any actions
  // and just return the state given to us.
  return state
}
```

一つの巧妙なトリックは、より多くのコンパクトな方法でこれを書くために[ES6 default arguments syntax](ES6 default arguments syntax)を使うことです:

```js
function todoApp(state = initialState, action) {
  // For now, don't handle any actions
  // and just return the state given to us.
  return state
}
```

`SET_VISIBILITY_FILTER`を取り扱ってみましょう。必要なことは、状態のなかで`visibilityFilter`を変えることです。簡単です:

```js
function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })
    default:
      return state
  }
}
```

注意点:

1. **我々は状態を変化させません。**我々は[Object.assign()](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)でコピーを作ります。`Object.assign(state, { visibilityFilter: action.filter })`もまた間違っています: 最初の引数が変化します。あなたは最初のパラメータとして空のオブジェクトを提供**しなければなりません。**またかわりに`{ ...state, ...newState }`と書くことで、[object spread operatorの提案](http://redux.js.org/docs/recipes/UsingObjectSpreadOperator.html)を有効にもできます。
2. **我々は`default`の場合には以前の`state`を返します。**どのような不明のActionのためにも以前の`state`を返すことは重要です。

> **`Object.assign`の注意**
> [Object.assign()](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)はES6の一部ですが、多くのブラウザにはまだ実装されていません。あなたはポリフィルである[Babel plugin](https://www.npmjs.com/package/babel-plugin-transform-object-assign)か、[_.assign()](https://lodash.com/docs#assign)のような他のライブラリからのヘルパーを使う必要があります。
> **`switch`と文例の注意**
> `switch`文は現実の文例ではありません。Fluxの現実の文例は概念上のものです: 更新を発行する必要、DispatcherとともにStoreを登録する必要、オブジェクトとなる（そしてあなたがユニバーサルなアプリを欲するときに困難化する）Storeの必要があります。Reduxはこれらの問題をイベント発行の代わりに単純なReducerを使うことで解決します。
>
> ドキュメントのなかで`switch`文が使われているかどうかを基礎とするフレームワークを多くのものがまだ選択していることは不幸です。もしあなたが`switch`を好きでないならば、あなたは[“reducing boilerplate”](http://redux.js.org/docs/recipes/ReducingBoilerplate.html#reducers)で示されているようにhandler mapを許可する慣習の`createReducer`関数を使うことができます。

## **より多くのActionを取り扱う**
我々は取扱いのために２つのActionを持ちます。`ADD_TODO`を取り扱うためにReducerを拡張しましょう。

```js
function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })
    case ADD_TODO:
      return Object.assign({}, state, {
        todos: [
          ...state.todos,
          {
            text: action.text,
            completed: false
          }
        ]
      })    
    default:
      return state
  }
}
```

ただ前のように、我々は決して`state`やフィールドを直接書きませんし、代わりに新しいオブジェクトを返します。新しい`todos`は一つの新しいアイテムを最後に連結された古い`todos`と同じです。新しいTodoはActionからのデータを使って構築されました。

最後に、`TOGGLE_TODO`ハンドラの実装は全く驚きではないでしょう:

```js
case TOGGLE_TODO:
  return Object.assign({}, state, {
    todos: state.todos.map((todo, index) => {
      if (index === action.index) {
        return Object.assign({}, todo, {
          completed: !todo.completed
        })
      }
      return todo
    })
  })
```

我々は変更に頼ることなしに配列の特定のアイテムを更新したいので、我々はindexのアイテムの除き同じアイテムを持つ新しい配列を作らなければなりません。もしあなたが自身でこのような処理に気づいたら、それは[react-addons-update](https://facebook.github.io/react/docs/update.html)や[updeep](https://github.com/substantial/updeep)のようなヘルパーや、深い更新をネイティブでサポートする[Immutable](http://facebook.github.io/immutable-js/)のようなライブラリでさえ使うのに良いアイデアです。ただ最初にクローンすることなしに`state`のなかでどんなものも割り当てることは決してしないということを覚えてください。

## **Reducerを分割する**
ここまでのコードはこちらです。かなり冗長です:

```js
function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })
    case ADD_TODO:
      return Object.assign({}, state, {
        todos: [
          ...state.todos,
          {
            text: action.text,
            completed: false
          }
        ]
      })
    case TOGGLE_TODO:
      return Object.assign({}, state, {
        todos: state.todos.map((todo, index) => {
          if(index === action.index) {
            return Object.assign({}, todo, {
              completed: !todo.completed
            })
          }
          return todo
        })
      })
    default:
      return state
  }
}
```

理解するのに簡単になる方法はないでしょうか？`todos`と`visibilityFilter`は完全に独立して更新されるように見えます。時々状態フィールドがほかに依存していたりするのでより検討が要求されますが、我々の場合では分割された関数へ更新した`todos`を簡単に分割することができます:

```js
function todos(state = [], action) {
  switch (action.type) {
    case ADD_TODO:
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
    case TOGGLE_TODO:
      return state.map((todo, index) => {
        if (index === action.index) {
          return Object.assign({}, todo, {
            completed: !todo.completed
          })
        }
        return todo
      })
    default:
      return state
  }
}

function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })
    case ADD_TODO:
    case TOGGLE_TODO:
      return Object.assign({}, state, {
        todos: todos(state.todos, action)
      })
    default:
      return state
  }
}
```

`todos`はまた`state`を受け取ることに注意してください。しかしそれは配列です！今`todoApp`はただ管理のために状態のいち部分を与えるのみで、`todos`はどのようにそのただ一部分を更新するかを知っています。**これはReducer構成とよばれ、Reduxアプリの構築の基本的なパターンです**

もっとReducer構築を探索しましょう。我々はまた`visibilityFilter`のみをReducerの管理から取り除くことができるでしょうか？できます:

```js
function visibilityFilter(state = SHOW_ALL, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return action.filter
    default:
      return state
  }
}
```

今、我々は状態のReducer管理部分と呼ばれる関数としての主となるReduverを書き換えることができ、一つのオブジェクトへそれらを組み合わせることができます。またこれ以上完全な初期状態を知る必要もありません。最初に`undefined`が与えられるときにそれらの初期状態を返す子Reducerは十分です。

```js
function todos(state = [], action) {
  switch (action.type) {
    case ADD_TODO:
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
    case TOGGLE_TODO:
      return state.map((todo, index) => {
        if (index === action.index) {
          return Object.assign({}, todo, {
            completed: !todo.completed
          })
        }
        return todo
      })
    default:
      return state
  }
}

function visibilityFilter(state = SHOW_ALL, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return action.filter
    default:
      return state
  }
}

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

**これらReducerの各々が自身のグローバルな状態の一部を管理していることに注意してください。`state`パラメータは全てのReducerで異なり、管理する状態の一部と比較します。**

これはすでによく見えます！アプリが大きいとき、我々は分割されたファイルにReduerを分割でき、それらを完全に独立し異なるデータドメインで管理するよう保ち続けることができます。

最後に、Reduxは、上で現在している`todoApp`である文例ロジックと同じように動作する[combineReducers()](http://redux.js.org/docs/api/combineReducers.html)とよばれるユーティリティを提供します。この助けで、我々はこのように`todoApp`を書き換えることができます:

```js
import { combineReducers } from 'redux'

const todoApp = combineReducers({
  visibilityFilter,
  todos
})

export default todoApp
```

これは完全に同等であることに注意してください:

```js
export default function todoApp(state = {}, action) {
  return {
    visibilityFilter: visibilityFilter(state.visibilityFilter, action),
    todos: todos(state.todos, action)
  }
}
```

あなたはまた異なるkeyをそれらに与え、異なるように関数を呼ぶでしょう。組み合わされたReducerを書くこれらの２つの方法は完全に同等です。

```js
const reducer = combineReducers({
  a: doSomethingWithA,
  b: processB,
  c: c
})
```

```js
function reducer(state = {}, action) {
  return {
    a: doSomethingWithA(state.a, action),
    b: processB(state.b, action),
    c: c(state.c, action)
  }
}
```

すべての[combineReducers()](http://redux.js.org/docs/api/combineReducers.html)のすることは、**それらのkeyによって選択された状態のいち部分と**あなたのReducerを呼び出す関数を生成し、再び一つのオブジェクトへ結果を組み合わせることです。[魔法ではありません。](https://github.com/reactjs/redux/issues/428#issuecomment-129223274)

> **ES6の知識を持ったユーザーへの注意**
> `combineReducers`がオブジェクトと思うので、我々は分割したファイルに全てのトップレベルのReducerを置くことができ、`export`でそれぞれのReducer関数、そしてkeyとしてそれらの名前とともにオブジェクトとしてそれらを得るために`import * as reducers`を使います。
>
> ```js
> import { combineReducers } from 'redux'
> import * as reducers from './reducers'
>
> const todoApp = combineReducers(reducers)
> ```
> 
> `import *`はまだ新しい構文なので、我々は[混乱](https://github.com/reactjs/redux/issues/428#issuecomment-129223274)を避けるためにドキュメントのなかでこれ以上それを使いませんが、あるコミュニティのサンプルではそれに遭遇するかもしれません。

## **ソースコード**

### **```reducers.js```**
```js
import { combineReducers } from 'redux'
import { ADD_TODO, TOGGLE_TODO, SET_VISIBILITY_FILTER, VisibilityFilters } from './actions'
const { SHOW_ALL } = VisibilityFilters

function visibilityFilter(state = SHOW_ALL, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return action.filter
    default:
      return state
  }
}

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

const todoApp = combineReducers({
  visibilityFilter,
  todos
})

export default todoApp
```

## **次のステップ**
次では、我々は、状態を持ちそしてあなたがアクションを送るときにReducerを呼び出すのを世話する[ReduxのStoreの作成](http://redux.js.org/docs/basics/Store.html)をどのようにするかを探索します。

_翻訳ここまで_

# **おわりに**
要約すると下記のとおりかと思います。

- Reducer
 - Actionによって状態を変化させる
 - 以前の状態とActionを受取り、新しい状態を返す
 - 上記以外の複雑な処理は決してしてはならない
 - 状態は前の状態をコピーし、それに手を加えて返す
 - 定義されていないActionが渡されたときのことも考慮する
 - Reducerを単純になるよう分割する

次は、[Redux Basics (3): Store 翻訳](http://qiita.com/uramonk/items/a6cfa3fa7f7c6827c2b1)です。