Search code examples
javascriptreactjsdesign-patternsreact-hooksusecallback

React.Js - useCallback inside a callback generator


I have a bunch of checkbox components and I want to update a state of the parent component each time the checkbox components are toggled. Right now I'm doing this:

   const selChangeHandler = useCallback(
    (checkboxId, isSel) => {
      if (isSel) setSelectedCheckboxes((prevState) => [...prevState, checkboxId]);
      else
        setSelectedCheckboxes((prevState) =>
          prevState.filter((x) => x != checkboxId)
        );
    },
    [setSelectedCheckboxes]
  );

This function is passed into each checkbox. I don't think that this is a particularly good approach as each checkbox can add anything to the array rather than only its id. So I tried this but I got an error:

  const GetSelChangeHandler = (checkboxId) => {
return useCallback(
  (isSel) => {
    if (isSel) setSelectedCheckboxes((prevState) => [...prevState, checkboxId]);
    else
      setSelectedCheckboxes((prevState) =>
        prevState.filter(
          (x) => x != checkboxId
        )
      );
  },
  [setSelectedCheckboxes]
); };

I executes this inline and passed the returned handler in as a callback prop to my checkbox components. I'm not sure what the error was but something to do with violating the rules of hooks. What is the correct way of doing this?


Solution

  • Rules of Hooks

    Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns.

    You should not use useCallback() inside GetSelChangeHandler, in case you're calling it conditionally.

    const GetSelChangeHandler = (checkboxId) => {
      return (isSel) => {
        if (isSel) setSelectedCheckboxes((prevState) => [...prevState, checkboxId]);
        else
          setSelectedCheckboxes((prevState) => prevState.filter(x => x !=checkboxId));
      };
    };