react-hooksでreduxを使う

# react-hooksでreduxを使う
案件でreactの改修が起きそうなので、react,redux,typescript,react-routerで気持ちよく書きたいと思い殴り書きだがサンプルを作って試してみました。

# 作ったリポジトリ
https://github.com/numa999/react-redux-example

# ざっくり解説
```tsx:router.tsx
import React from 'react'
import { BrowserRouter, Route, Link } from 'react-router-dom'

import App from './App'
import Counter from './counter'

const Router: React.FC = () => (
  <BrowserRouter>
    <nav>
      <ul>
        <li><Link to="/">HOME</Link></li>
        <li><Link to="/counter">COUNTER</Link></li>
      </ul>
    </nav>
    <hr/>
    <div className="content">
      <Route exact path="/" component={ App } />
      <Route path="/counter" component={ Counter } />
    </div>
  </BrowserRouter>
)

export default Router
```
ここは特に工夫していないです。ナビゲーションも適当。

```tsx:counter.tsx
import React, { useState } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { RootState, incrementActionCreator, decrementActionCreator } from './store';

const Counter: React.FC = () => {
  const [count, setCount] = useState(0)
  const dispatch = useDispatch()
  const counterState = useSelector((state: RootState) => state.counter)

  return (
    <div>
      react hooks count { count }
      <div>
        <button onClick={() => setCount(count + 1)}>+</button>
        <button onClick={() => setCount(count - 1)}>-</button>
      </div>
      redux count { counterState.count }
      <div>
        <button onClick={() => dispatch(incrementActionCreator())}>+</button>
        <button onClick={() => dispatch(decrementActionCreator())}>-</button>
      </div>
    </div>
  )
}

export default Counter
```
react-hooksもそんな使ってないのでちょっと余計なコードも追加。

## useSelector
前までの `mapStateToProps` の代わり
https://react-redux.js.org/next/api/hooks#useselector

## useDispatch
storeのdispatchを生成してくれる。アクションの中身を指定して渡してあげる。useCallbackは一旦省略。
https://react-redux.js.org/next/api/hooks#usedispatch

## store
```javascript:store.ts
import { combineReducers, createStore } from 'redux'

// Counter State
interface CounterState {
  count: number
}

const counterInitialState: CounterState = {
  count: 0
}

// actions
export const INCREMENT = 'COUNTER/INCREMENT'
export const DECREMENT = 'COUNTER/DECREMENT'

interface IncrementAction {
  type: typeof INCREMENT
  payload: null
}

interface DecrementAction {
  type: typeof DECREMENT
  payload: null
}

type CounterActionTypes = IncrementAction | DecrementAction

export const incrementActionCreator = (): CounterActionTypes => {
  return {
    type: INCREMENT,
    payload: null
  }
}

export const decrementActionCreator = (): CounterActionTypes => {
  return {
    type: DECREMENT,
    payload: null
  }
}
//---

// reducers
export const counterReducer = (
  state = counterInitialState,
  action: CounterActionTypes
): CounterState => {
  switch (action.type) {
    case INCREMENT:
      return { count: state.count + 1 }
    case DECREMENT:
      return { count: state.count - 1 }
    default:
      return state
  }
}
//---

// combine
export const rootReducer = combineReducers({
  counter: counterReducer
})

export type RootState = ReturnType<typeof rootReducer>

export const store = createStore(rootReducer)
```
`ReturnType` 知らなかった。
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#example-4

# 感想
ここにreset用のアクションとか付け足したいけど省略。最近vuexばっかり使っていたので、比較でもないですが僕はやっぱりreactの方が好きだなと思った。


# 参考
https://react-redux.js.org/next/api/hooks
https://redux.js.org/recipes/usage-with-typescript
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html
https://qiita.com/seya/items/8291f53576097fc1c52a