3

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?

spspli
  • 3,128
  • 11
  • 48
  • 75
  • "I get error in my custom hook, saying "Cannot read properties of undefined (reading 'object1Name')"" - but didn't you convert the custom hook to a utility function to call instead? Or is the error occurring in either the `myData` mapping or the `handleSelect` callback? – Drew Reese Nov 17 '21 at 20:07
  • @DrewReese seems the error occurs here const { setTwoObjects } = useSetMyObjects(); when I convert the custom hook to function, there is no parameter pass to the custom hook and so the parameter is undefined, and hence sourceObjectName is property of undefined...so the error throws? – spspli Nov 17 '21 at 23:20
  • I guess that's what I don't understand, you said you converted the `useSetMyObjects` hook into a regular function so you could call it, why are you still using the hook and attempting to destructure from it? It also doesn't appear to return anything to destructure from. – Drew Reese Nov 17 '21 at 23:24
  • What would be the correct way to convert the custom hook to a function? I may miss that. Actually not too much idea how to do that... – spspli Nov 17 '21 at 23:56
  • Oh, I think I see what you are trying to. I think I misunderstood what you said you had completed already. So you are trying to return a function from the hook that you can then invoke manually to dispatch the two actions? – Drew Reese Nov 17 '21 at 23:58
  • Yes! Is that possible to do that? Sorry for not state it clearly! – spspli Nov 18 '21 at 00:00

1 Answers1

11

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,
    },
  );
};
spspli
  • 3,128
  • 11
  • 48
  • 75
Drew Reese
  • 165,259
  • 14
  • 153
  • 181