With react useDispatch() hook how to rename method like in connect

Viewed 337

Previously we could do something like this:

  export default connect(
  (state) => {
    const { data } = state.Something;
    ...
    return {
     data
    };
  },
  (dispatch) =>
    bindActionCreators(
      {
        getAdmins: (id) =>
          getAdminsList(id),
      },
      dispatch
    )
)(ComponentName);

With the useDispatch() Hook, how to achieve the same thing of renaming getAdminsList(id) as getAdmins(id)? The normal way is:

const dispatch = useDispatch();

Then use it as dispatch(getAdminsList(id)); How do I rename it to getAdmins(id)? Thanks.

2 Answers

Assuming that getAdminList function is defined in a different file you can simply use alias to rename it.

import { getAdminList as getAdmin} from './your-file'

Create a custom hook named useActions which use bindActionCreators underly. Then you can pass your action creators to useActions with the alias.

import { ActionCreator, ActionCreatorsMapObject, bindActionCreators } from 'redux';
import { useDispatch } from 'react-redux';
import { DependencyList, useMemo } from 'react';

function useActions<A extends ActionCreator<any>>(actions: A[]): A[];
function useActions<A extends ActionCreatorsMapObject>(actions: A): A;
function useActions(actions: any, deps?: DependencyList): any {
  const dispatch = useDispatch();
  return useMemo(
    () => {
      if (Array.isArray(actions)) {
        return actions.map((a) => bindActionCreators(a, dispatch));
      }
      return bindActionCreators(actions, dispatch);
    },
    deps ? [dispatch, ...deps] : [dispatch],
  );
}

export default useActions;

test:

import { renderHook } from '@testing-library/react-hooks';
import React from 'react';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import useActions from './useActions';

describe('useActions', () => {
  test('should pass', () => {
    const store = createStore(() => {
      return null;
    });
    function getAdminsList(payload) {
      return { type: 'GET_ADMIN_LIST', payload };
    }
    function wrapper({ children }) {
      return <Provider store={store}>{children}</Provider>;
    }
    const { result } = renderHook(() => useActions({ getAdmins: getAdminsList }), { wrapper });
    const action = result.current.getAdmins(1);
    expect(action).toEqual({ type: 'GET_ADMIN_LIST', payload: 1 });
  });
});

test result:

 PASS   redux-toolkit-example  packages/redux-toolkit-example/examples/use-actions/useActions.test.tsx
  useActions
    ✓ should pass (21 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.218 s

Usage: since the action creators are bound to dispatch, you can call them directly without using useDispatch() again in your component. It's more advanced than using the import alias.

function App() {
  const actions = useActions({ getAdmins: getAdminsList });
  useEffect(() => {
    actions.getAdmins(1)
  }, [actions])

  return <div>...</div>
}
Related