redux素晴らしい
パフォーマンス良し、テスト良し、デバッグ良し、エコシステム良し。
私はreact nativeの人なのですが、redux-persistを使いたいために、2019年でもreduxを使い続けると思います。
ただreduxにも弱点があります。学習コストの高さと、記述量の多さです。
そのため、reduxの記述量を減らすためのライブラリが数多く生み出されてきました。
redux-actions, redux-sauce, etc...
時代はES6へ変わりました、現代風のreduxの書き方で記述量を半分にダイエットしましょう。
完成品は以下のurlにあります。
https://github.com/soniczsonic/reduxtuto/tree/master
一般的なreduxの書き方
userの名前を扱うreduxです。
// redux.js
export const deleteName = () => ({
type: 'DELETE_NAME',
name: ''
});
export const setName = name => ({
type: 'ADD_NAME',
name: name,
});
INITIAL_STATE = {
name: 'Nanasi'
}
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case 'ADD_NAME':
return {...state, name: action.name}
case 'DELETE_NAME':
return {...state, name: ''}
default:
return state;
}
}
よくあるswitch文です。記述量が多いですね。
ここで目をつけるのが一箇所。
##そもそもAcrion creator いらないのでは
そう、今回はactionを直接viewに書き込みます。意外にも、スッキリしたコードになります。
(ただし、この書き方はredux-thunkとは併用できません。redux-sagaか、redux-observableなどを使いましょう)
まずjsのオブジェクトについておさらい
- オブジェクトリテラル。
オブジェクトリテラルとは{}で囲むとオブジェクトを作ることができる構文です。new classとだいたい同じです。
つまり、
obj = {name: 'kabaya' sayName: () => console.log('kabaya desu.')}
と書けます。
obj.nameとobj.sayNameを実行してみましょう。
2.hasOwnProperty
objectが特定のkeyを持っているかを真偽値で返します。
obj.hasOwnProperty('name') // true
obj.hasOwnProperty('sex') // false
以上のことを後で使うので覚えておいてください。
reduxをダイエット。
まず用意するのは以下のcreateReducer関数です。純粋なjsで作ったスニペットです。
jsのカリー化を使ってfunction fucoryと呼ばれるものを作ります。
つまり、functinonを作成するためのfunctionを作ります。
// createReducer.js
export function createReducer(initialState, actionHandlers) {
return function reducer(state = initialState, action) {
if (actionHandlers.hasOwnProperty(action.type)) {
return actionHandlers[action.type](state, action)
} else {
return state
}
}
}
上のcreateReducer関数を使うと、reduxが以下のように書けます。
// superUserRedux.js
import createReducer from './createReducer'
INITIAL_STATE = {
name: 'Super User',
age: 16
}
const actions = {
SET_SUPER_USER_NAME: (state, action) => ({...state, name: action.name, age: action.age}),
DELETE_SUPER_USER: (state, action) => ({...state, name: '', age: 0})
}
export default createReducer(INITIAL_STATE, actions)
type: 'ACTION'と直接書き込みます。
// heme.js
const mapDispatchToProps = dispatch => ({
// actionCreatorをimportした場合
setName: (name) => dispatch(setName(name)),
deleteName: () => dispatch(deleteName()),
// actionCreatorをimportしない場合。
setSuperUser: (name, age) => dispatch({type: 'SET_SUPER_USER_NAME', name, age}),
deleteSuperUser: () => dispatch({type: 'DELETE_SUPER_USER'}),
})
注意
dispatchの中のactionのプロパティと、reducerの引数の名前は一致している必要があります。
つまり、
setSuperUser: (name1, age) => dispatch({type: 'SET_SUPER_USER_NAME', name1, age})
とした場合は、
reducerの方でも
SET_SUPER_USER_NAME: (state, action) => ({...state, name: action.name1, age: action.age})
とnameをname1に変えてあげる必要があります。
なぜかというと、dispatch()の引数は、reducerにactionという形で渡されるからです。
つまり、
SET_SUPER_USER_NAME: (state, action)のactionの中身は{type: 'SET_SUPER_USER_NAME', name, age}ということです。
さらに簡潔に
mapDispatchToProopsのショートハンドを使いましょう。
実は、dispatchを使わずに、action creatorを直接、mapDispatchToPropsに書き込めます。
// heme.js
const mapDispatchToProps = {
// actionCreatorをimportした場合
setName,
deleteName,
// actionCreatorをimportしない場合。
setSuperUser: (name, age) => ({type: 'SET_SUPER_USER_NAME', name, age}),
deleteSuperUser: () => ({type: 'DELETE_SUPER_USER'}),
}
ES6の力は偉大ですね。
純粋なjsだけでこれほどreduxの記述量を減らすことができました。
参考url
https://medium.freecodecamp.org/reducing-the-reducer-boilerplate-with-createreducer-86c46a47f3e2