reactjsreact-reduxreact-hooksarrow-functionsredux-reducers

How to pass the parameters to a function converted from custom hook?


I have a custom hook, it will fire two actions in my Redux slice "myTestSlice", action1 and action2, behind each action, I have reducer function to get new state.

const useSetMyObjects = (
    actions,
    { object1Name, object1Id, object2Name, object2Id }, // here throws the error cannot read property of undefined when I call the function converted from this custom hook
) => {
    const dispatch = useDispatch();

    useEffect(() => {
        dispatch(actions.action1({ object1Name, object1Id }));
    }, [object1Name, object1Id, actions, dispatch]);

    useEffect(() => {
        dispatch(
            actions.action2({
                object2Name,
                object2Id
            }),
        );
    }, [object2Name, object2Id, actions, dispatch]);
};

export default useSetMyObjects;

I have a react component, I want to use this custom hook in an array loop and also in an event handler. So I have to turn this custom hook to a function to use it, otherwise I get warning:

React Hook "useSetMyObjects" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function

But I have no idea how to convert this custom hook to a function.

Here is how I will use the function converted from the custom hook:

I want to use function setTwoObjects in an useEffect:

useEffect(() => {
        myData.map((data) =>
            useSetMyObjects(myTestSlice.actions, {//supposed to use that converted function instead of useSetMyObjects here, but no idea how
                object1Name: data.object1Name,
                object1Id: data.object1Id,
                object2Name: data.object2Name,
                object2Id: data.object2Id
            }),
        );
    }
}, [myData, useSetMyObjects]);

And I also use the function setTwoObjects in an event handler:

const handleSelect = (e, value) => {
        const newData = value;

        useSetMyObjects(myTestSlice.actions, {//supposed to use that converted function instead of useSetMyObjects here, but no idea how
            object1Name: newData.object1Name,
            object1Id: newData.object1Id,
            object2Name: newData.object2Name,
            object2Id: newData.object2Id,
        });
    }
};

How can I convert the custom hook to a function so I can call it in the callback or an event handler?


Solution

  • Instead of the useSetMyObjects hook taking the arguments, you want the hook to return a function that takes the arguments and wraps the actions in the call to dispatch for you.

    const useSetMyObjects = () => {
      const dispatch = useDispatch();
    
      const setTwoObjects = (
        actions,
        { object1Name, object1Id, object2Name, object2Id },
      ) => {
        dispatch(actions.action1({ object1Name, object1Id }));
        dispatch(actions.action2({ object2Name, object2Id }));
      };
    
      return setTwoObjects;
    };
    

    Usage:

    const setTwoObjects = useSetMyObjects();
    

    ...

    useEffect(() => {
      myData.map((data) =>
        setTwoObjects(
          myTestSlice.actions,
          {
            object1Name: data.object1Name,
            object1Id: data.object1Id,
            object2Name: data.object2Name,
            object2Id: data.object2Id
          },
        )
      );
    }, [myData, useSetMyObjects]);
    

    ...

    const handleSelect = (e, value) => {
      const newData = value;
    
      setTwoObjects(
        myTestSlice.actions,
        {
          object1Name: newData.object1Name,
          object1Id: newData.object1Id,
          object2Name: newData.object2Name,
          object2Id: newData.object2Id,
        },
      );
    };