bindActionCreators – маленька утиліта, що вирішує проблеми.
Бібліотеки redux
або@reduxjs/toolkit
надають велику кількість корисних утиліт, у цій статті я розповім про одну з них – bindActionCreators
Одна з проблем, що переслідує майже всіх, хто використовує вищезгадані бібліотеки – неможливість використання action()
, попередньо не обернувши його в dispatch()
. Це породжує велику кількість безглуздого коду:
const dispatch = useDispatch()
const handleReset = (id: number) => dispatch(actionReset(id))
Як використовувати bindActionCreators?
Спочатку розберемося з аргументами:bindActionCreators(actionCreators, dispatch)
actionCreators
– об’єкт виду{ actionName: ActionDefinition }
dispatch
– відповідноdispatch
зuseDispatch()
абоstore
Далі розберемо два способи використання за вищезгаданими методами одержанняdispatch
Хук useDispatchedActions і useDispatch
const useDispatchedActions = (actionCreators) => {
const dispatch = useDispatch()
return bindActionCreators(actionCreators, dispatch)
}
Або в один рядок:
const useDispatchedActions = (actionCreators) => bindActionCreators(actionsCreators, useDispatch())
Також приклад цього хук на TypeScript з прикладом типів
type Store = typeof store
type AppDispatch = typeof Store['dispatch']
type BoundAsyncThunk<Actionы extends ActionCreator<any>> = (
...args: Parameters<Action>
) => ReturnType<ReturnType<Action>>
type BoundActions<Actions extends ActionCreatorsMapObject> = {
[key in keyof Actions]: Actions[key] extends AsyncThunk<any, any, any>
? BoundAsyncThunk<Actions[key]>
: Actions[key]
}
const useDispatchedActions = <Actions extends ActionCreatorsMapObject = ActionCreatorsMapObject> (
actions: Actions,
): BoundActions<Actions> => {
const dispatch = useDispatch<AppDispatch>()
return bindActionCreators(actions, dispatch), [actions, dispatch]
}
Власна утиліта та store.dispatch
const getDispatchedActions = (actionsCreators) => bindActionCreators(actionsCreators, store.dispatch)
Результат же – той самий об’єкт, який ми передавали в аргумент з однією відзнакою – ці екшени ми можемо використовувати без необхідності обертати їх викликdispatch()
Я б рекомендував вам використовувати другий метод використання bindActionCreators
з двох причин:
- Метод універсальніший, не змушує вас використовувати його тільки в інших хуках чи компонентах
- Якщо ви будете використовувати хук
useDispatchedActions
, вам необхідно враховувати, що екшени, які ви отримуватимете з хука і використовуватимете в компонентах,eslint
вимагатиме додати їх залежно від іншихReact
хуків. А це може призвести до несподіваних помилок (наприклад, до нескінченних викликівuseEffect
).