bindActionCreators – маленька утиліта, що вирішує проблеми.

redux Бібліотеки 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).

Джерело