Reduxをざっくり理解する

Reactを使う上で切っても切れないのがReduxによる状態管理。
頑張って覚えるぞい。

# 読んだ記事

## 基本をおさえる
そもそもReduxってなんなの？状態だったので記事を漁る。
この辺でまず前提の知識は備わった。

- Fluxについての簡単なまとめ: https://qiita.com/yshimooka/items/c0305f4efa49dc020487
- Redux入門【ダイジェスト版】10分で理解するReduxの基礎: https://qiita.com/kitagawamac/items/49a1f03445b19cf407b7

## 最新のReduxを学ぶ
[前回の記事](https://qiita.com/kuz/items/139f5801557fbbc91a39)でReact hooksを覚えたので、それに絡めたReduxの使い方をお勉強。

- Redux Hooks によるラクラク dispatch & states: https://qiita.com/Ouvill/items/569384e5c8c7ce78f98e
- Redux 公式ドキュメント Hooks: https://react-redux.js.org/api/hooks

# なるほど、わからん
読んだだけではちゃんとわからん。
個人的な解釈を整理する。

## 1.Actionを作る
Storeに対してやりたいことを書いておく。
`type`は必須。あとで使う。
値を流す場合は受け渡しの処理を書く。

```react
// Action
export const setComment = (comment) => 
 ({
    type: 'setComment',
    comment
  });
```
## 2. Reducerを作る
Actionの受け口で、Storeへのアクセスを管理する。
Actionで設定した`type`に対応した処理を書く。

```react
// Reducer
export const reducer = (state = {comment: null}, action) => {
  switch (action.type) {
    case 'setComment': {
      console.log(action);
      return { ...state, comment: action.comment };
    }
    default: {
      return state;
    }
  }
}
```

## 3. Storeを作る
データを保持しておくところ。
メモリー常にFirebaseみたいなのを作るイメージ。
値を変更する時は必ずActionを通す。

```react
// Store
export default createStore(combineReducers({foo :reducer}));
```

以上を踏まえたファイルがこちら。

```react:redux.js
import { createStore, combineReducers } from 'redux';
import { useSelector, useDispatch } from 'react-redux';

// Action
export const setComment = (comment) => 
 ({
    type: 'setComment',
    comment
  });

// Reducer
export const reducer = (state = {comment: null}, action) => {
  switch (action.type) {
    case 'setComment': {
      console.log(action);
      return { ...state, comment: action.comment };
    }
    default: {
      return state;
    }
  }
}

// Store
export default createStore(combineReducers({foo :reducer}));
```

## 4. Storeに値を入れる
ではいよいよ使っていきます。
さっきも言ったようにStoreにデータを投入するときはAction->Reducerを経由しなければならない。
具体的にどうするかというと、ActionをDispatchする。

```react
export const CommentForm = () => {
  const ref = useRef();
  const dispatch = useDispatch();

  return (
    <div>
      <input ref={ref} type="text" />
      <button onClick={() => dispatch(setComment(ref.current.value))}>comment</button>
    </div>
  );
}
```
ReduxにもHooks APIがあり、それを使うことで簡単に書けた。

(2019/09/06 追記)
子コンポーネントにdispatchさせる時は`useCallback`を使ってコールバック関数の参照が変わらないようにする。

```react
export const CommentForm = () => {
  const ref = useRef();
  const dispatch = useDispatch();
  const setCommenter = useCallback(
    () => dispatch(setComment(ref.current.value)),
    [dispatch]
  )

  return (
    <div>
      <input ref={ref} type="text" />
      <CommentButton onSetComment={setCommenter} />
    </div>
  );
}

export const CommentButton = React.memo(({ onSetComment }) => (
  <button onClick={onSetComment}>comment</button>  
))
```

## 5. Storeから値を取得
こちらもHooks APIを使う。

```react
export const Comment = () => {
  const comment = useSelector(state => state.foo.comment);
  return (
    <div>{comment}</div>
  );
}
```

`state`の次に来るプロパティのキーはStore作成時に設定できる。
ES6ならそのまま入れれば変数名がキーになる。

```react
// Store
export default createStore(combineReducers({reducer}));
```

```react
export const Comment = () => {
  const comment = useSelector(state => state.reducer.comment);
  return (
    <div>{comment}</div>
  );
}
```

# サンプルコード
前回hooksを試したやつを改造したサンプルコードが[こちら](https://stackblitz.com/edit/react-3w1tdh)

---
だいたい分かった。