![見出し画像](https://assets.st-note.com/production/uploads/images/80475012/rectangle_large_type_2_8130fd8d995bca2ab82d9e1e3dd537ac.png?width=1200)
Redux-actionsにコメントつけてみた
本家のURL
https://redux-actions.js.org/
import { createActions, handleActions, combineActions } from 'redux-actions';
const defaultState = { counter: 10 };
const { increment, decrement } = createActions({
INCREMENT: (amount = 1) => ({ amount }),
DECREMENT: (amount = 1) => ({ amount: -amount })
});
const reducer = handleActions(
{
[combineActions(increment, decrement)]: (
state,
{ payload: { amount } }
) => {
return { ...state, counter: state.counter + amount };
}
},
defaultState
);
export default reducer;
■ Motivation
Reduxはデータstoreの変異を予測可能にしたが、同時に冗長にもしてしまった。
このツールはその点を考慮して作られたものです。豊富な定型文は書くのもの読むのも苦痛になることがあります。
Action CreatorsとReducersの文字列定数を追跡することは初心者には負担になります。
■API Reference
createAction(s)
createAction
// createActionにtypeを渡すとaction creatorを返す。
createAction(
type, // stringのみ、入力必須
payloadCreator = Identity,
?metaCreator
)
// 具体例
export const increment = createAction('INCREMENT');
export const decrement = createAction('DECREMENT');
increment(); // { type: 'INCREMENT' }
decrement(); // { type: 'DECREMENT' }
increment(10); // { type: 'INCREMENT', payload: 10 }
decrement([1, 42]); // { type: 'DECREMENT', payload: [1, 42] }
// payloadにError objectが渡されると、redux-actionsは自動でaction.errorをtrueにする。
const noop = createAction('NOOP');
const error = new TypeError('not a number');
expect(noop(error)).to.deep.equal({
type: 'NOOP',
payload: error,
error: true
});
// handleActionかhandleActionsの中ではcreateActionはtypeを返す。
const noop = createAction('INCREMENT');
// As parameter in handleAction:
// noopはtypeとして利用できる
handleAction(noop, {
next(state, action) {...},
throw(state, action) {...}
});
// As object key in handleActions:
// noopはtypeとして利用できる
const reducer = handleActions({
[noop]: (state, action) => ({
counter: state.counter + action.payload
})
}, { counter: 0 });
// 単発のActionを作成するためにidentiy formを利用します。
createAction('ADD_TODO')('Use Redux');
// metaCreatorはoptional functionになります。
const updateAdminUser = createAction(
'UPDATE_ADMIN_USER',
updates => updates,
() => ({ admin: true })
);
updateAdminUser({ name: 'Foo' });
// {
// type: 'UPDATE_ADMIN_USER',
// payload: { name: 'Foo' },
// meta: { admin: true },
// }
createActions
createActions(
actionMap,
?...identityActions,
?options
)
// 具体例
createActions({
ADD_TODO: todo => ({ todo }), // payload creator
REMOVE_TODO: [
todo => ({ todo }), // payload creator
(todo, warn) => ({ todo, warn }) // meta
]
});
// options
createActions({ ... }, 'INCREMENT', {
prefix: 'counter', // String used to prefix each type
namespace: '--' // Separator between prefix and type. Default: `/`
})
'INCREMENT'は'counter--INCREMENT'になる
handleAction(s)
handleAction
handleAction(
type,
reducer | reducerMap = Identity,
defaultState,
)
具体例
handleAction(
'APP/COUNTER/INCREMENT', // type
(state, action) => ({ // reducer
counter: state.counter + action.payload.amount
}),
defaultState // defaaultState
);
// next(), throw()を明示的に使用する例
// next(): Actionが正常終了した時の処理
// throw(): Actionが異常終了した時の処理
handleAction('FETCH_DATA', {
next(state, action) {...},
throw(state, action) {...},
}, defaultState);
handleActions
handleActions(reducerMap, defaultState);
// 具体例
const reducer = handleActions(
{
INCREMENT: (state, action) => ({
counter: state.counter + action.payload
}),
DECREMENT: (state, action) => ({
counter: state.counter - action.payload
})
},
{ counter: 0 }
);
// optionsの具体例
const options = {
prefix: 'counter', // String used to prefix each type
namespace: '--' // Separator between prefix and type. Default: `/`
}
createActions({ ... }, 'INCREMENT', options)
handleActions({ ... }, defaultState, options)
combineActions
// 任意の数のActionTypeとActionCreatorsを組み合わせる
//
combineActions(...types);
// handleActionとcombineActionsの例
const { increment, decrement } = createActions({
INCREMENT: amount => ({ amount }),
DECREMENT: amount => ({ amount: -amount }),
})
const reducer = handleAction(combineActions(increment, decrement), {
next: (state, { payload: { amount } }) => ({ ...state, counter: state.counter + amount }),
throw: state => ({ ...state, counter: 0 }),
}, { counter: 10 })
expect(reducer(undefined, increment(1)).to.deep.equal({ counter: 11 })
expect(reducer(undefined, decrement(1)).to.deep.equal({ counter: 9 })
expect(reducer(undefined, increment(new Error)).to.deep.equal({ counter: 0 })
expect(reducer(undefined, decrement(new Error)).to.deep.equal({ counter: 0 })
// handleActionsとcombineActionsの例
const { increment, decrement } = createActions({
INCREMENT: amount => ({ amount }),
DECREMENT: amount => ({ amount: -amount })
});
const reducer = handleActions(
{
[combineActions(increment, decrement)]: (
state,
{ payload: { amount } }
) => {
return { ...state, counter: state.counter + amount };
}
},
{ counter: 10 }
);
expect(reducer({ counter: 5 }, increment(5))).to.deep.equal({ counter: 10 });
expect(reducer({ counter: 5 }, decrement(5))).to.deep.equal({ counter: 0 });
expect(reducer({ counter: 5 }, { type: 'NOT_TYPE', payload: 1000 })).to.equal({
counter: 5
});
expect(reducer(undefined, increment(5))).to.deep.equal({ counter: 15 });
この記事が気に入ったらサポートをしてみませんか?