概要
1日 Redux を触って既存のコンポーネントを書き換えていきました。サンプルやドキュメントはいきなり完成形のコンポーネントについて説明するものが多く分かりづらかったので、忘備録としてここにまとめます。
ステップバイステップで単純なコンポーネントから Redux で非同期処理を行うコンポーネントを作っていきます。
Redux のセットアップや store の作り方などは触れません。
1. Stateless Component を作る
固定の情報を表示するだけのものを作ります
export default function HelloComponent(props) {
return <p>Hello, {props.name}!</p>
}
HelloComponent.propTypes = {
PropTypes.string.isRequired
}
2. Redux と接続する
一枚岩 state から必要な情報を加工して props に変換する mapStateToProps
を追加します。
connect()
に渡して Redux と接続されたコンポーネントを作ります。
function HelloComponent(props) {
return <p>Hello, {props.name}!</p>
}
HelloComponent.propTypes = {
PropTypes.string.isRequired
}
// ログイン済みユーザーの情報 state.user からユーザー名を取り出して props.name に変換する
function mapStateToProps(state) {
return {
name: state.user && state.user.name
}
}
export default connect(mapStateToProps)(HelloComponent)
3. イベントハンドリング
押した時にログアウトを行うボタンを追加します
Action を作成する
ログアウトする Action Creator を作ります。
- アクションを識別する type の文字列
- アクションを生成する関数 (Action Creator)
export const SET_USER = "SET_USER"
// Action Creator
export function setUser(user) {
return {
type: SET_USER,
user: user
}
}
Action はこの Action Creator が返すオブジェクトのことです
Reducer を作成する
SET_USER に対応する state の遷移を実装します
import { combineReducers } from "redux"
import { SET_USER } from "./actions"
function user(state = null, action) {
switch(action.type) {
case SET_USER:
return action.user
default:
return state
}
}
export default combineReducers({
user
})
Component 側の変更
ボタンを押した時に state.user を null にしてログアウトしたことにします。
onClick のようなイベントからアクションを生成する mapDispatchToProps
を追加します。
import { setUser } from "./actions"
function HelloComponent(props) {
return <div>
<p>Hello, {prop.name}!</p>
<button onClick={props.onClickLogout}>Logout</button>
</div>
}
HelloComponent.propTypes = {
PropTypes.string.isRequired
}
function mapStateToProps(state) {
return {
name: state.user && state.user.name
}
}
function mapDispatchToProps(dispatch) {
return {
onClickLogout: () => { dispatch(setUser(null)) }
}
}
export default connect(mapStateToProps, mapDispatchToProps)(HelloComponent)
4. 非同期処理
一番簡単だと思った redux-thunk
ミドルウェアによる方法を説明します。
Action の変更
ログアウト API を叩き、成功時に setUser() で null をセットする非同期 Action を追加します。
非同期 Action は dispatch を引数にとる関数を返す関数として定義されます。
この関数は redux-thunk
ミドルウェアが導入されていない場合エラーになります。
export const SET_USER = "SET_USER"
// Action Creator
export function setUser(user) {
return {
type: SET_USER,
user: user
}
}
export const logout = () = dispatch => {
exampleApi.logout(error => {
if (!error) {
dispatch(setUser(null))
}
})
}
コンポーネントの変更
setUser(null) を logout() に変えます。
import { logout } from "./actions"
function HelloComponent(props) {
return <div>
<p>Hello, {prop.name}!</p>
<button onClick={props.onClickLogout}>Logout</button>
</div>
}
HelloComponent.propTypes = {
PropTypes.string.isRequired
}
function mapStateToProps(state) {
return {
name: state.user && state.user.name
}
}
function mapDispatchToProps(dispatch) {
return {
onClickLogout: () => { dispatch(logout()) }
}
}
export default connect(mapStateToProps, mapDispatchToProps)(HelloComponent)
所感
Redux を始めたばかりですが、思ったより地道に書き換える事ができてよかったです。非同期処理まわりはいろんな方法があるそうなので、規模に合わせていい感じの書き方を学んでいきたいと思います。