Home > other >  Uncaught Error: Invalid hook call, when calling return function of a hook
Uncaught Error: Invalid hook call, when calling return function of a hook

Time:11-08

When calling a function that gets returned from a custom hook (useOutput) in one of my components, I get an Invalid hook call error with the following message:

Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
    at Object.throwInvalidHookError (plugin:flow:17739:539)
    at useRef (plugin:flow:1768:25)
    at useSyncExternalStoreWithSelector (plugin:flow:3976:21)
    at useStore$1 (plugin:flow:4083:17)
    at useBoundStore (plugin:flow:4089:51)
    at useOutput (plugin:flow:13158:9)
    at setOutput (plugin:flow:13195:45)
    at onClickButton (plugin:flow:13200:9)
    at HTMLUnknownElement.callCallback (plugin:flow:15894:119)
    at Object.invokeGuardedCallbackDev (plugin:flow:15914:45)
throwInvalidHookError @ plugin:flow:17739
useRef @ plugin:flow:1768
useSyncExternalStoreWithSelector @ plugin:flow:3976
useStore$1 @ plugin:flow:4083
useBoundStore @ plugin:flow:4089
useOutput @ plugin:flow:13158
setOutput @ plugin:flow:13195
onClickButton @ plugin:flow:13200
callCallback @ plugin:flow:15894
invokeGuardedCallbackDev @ plugin:flow:15914
invokeGuardedCallback @ plugin:flow:15933
invokeGuardedCallbackAndCatchFirstError @ plugin:flow:15942
executeDispatch @ plugin:flow:16822
processDispatchQueueItemsInOrder @ plugin:flow:16822
processDispatchQueue @ plugin:flow:16822
dispatchEventsForPlugins @ plugin:flow:16824
eval @ plugin:flow:16878
batchedEventUpdates$1 @ plugin:flow:19004
batchedEventUpdates @ plugin:flow:15839
dispatchEventForPluginEventSystem @ plugin:flow:16878
attemptToDispatchEvent @ plugin:flow:16266
dispatchEvent @ plugin:flow:16244
unstable_runWithPriority @ plugin:flow:14064
runWithPriority$1 @ plugin:flow:17299
discreteUpdates$1 @ plugin:flow:19005
discreteUpdates @ plugin:flow:15839
dispatchDiscreteEvent @ plugin:flow:16234

This is my code:

Inside react component:

const flowName = useContext(FlowNameContext);
const setOutput = (output: OutputData, outputId: string) =>
  useOutput(outputId, id, flowName)[1](output);

useOutput hook

export const useOutput = (
  outputId: string,
  nodeId: string,
  flowName: string
): MutableHookResult<OutputData> => {
  return [
    useAppModel(
      (store) =>
        selectOutputs(nodeId, selectFlow(flowName, store)?.editorModel)[
          outputId
        ]
    ),
    (output: OutputData) =>
      useAppModel.setState(
        produce((draft: AppModel) => {
          setOutput(output, outputId, nodeId, flowName, draft);
        })
      ),
  ];
};

setOutput function:

export const setOutput = (
  output: OutputData,
  id: string,
  nodeId: string,
  flowName: string,
  appModel: AppModel
): void => {
  // update outputs
  const editorModel = selectFlow(flowName, appModel).editorModel;
  const node = selectNode(nodeId, editorModel);
  if (node) node.data.outputs[id] = output;

  // update inputs
  const connectedNodes = selectConnectedNodes(nodeId, false, id, editorModel);

  connectedNodes.forEach((connectedNode) => {
    connectedNode.node.data.inputs[connectedNode.connectedOn] = output;
  });
};

(the select functions are just helpers to select properties of the state object, they are vanilla ts)

What's the issue here?

CodePudding user response:

You can't call hook inside the function. hooks need to be initialized in the component level.

One thing you can do is create a subfunction inside useOutput and return the content

export const useOutput = () => {

  const getResult = (outputId: string, nodeId: string, flowName: string): MutableHookResult<OutputData>  => {
   return [
    useAppModel(
      (store) =>
        selectOutputs(nodeId, selectFlow(flowName, store)?.editorModel)[
          outputId
        ]
    ),
    (output: OutputData) =>
      useAppModel.setState(
        produce((draft: AppModel) => {
          setOutput(output, outputId, nodeId, flowName, draft);
        })
      ),
   ];
  }

  return {getResult}
 
};

component

const {getResult} = useOutput();
const setOutput = (output: OutputData, outputId: string) =>
  getResult(outputId, id, flowName)[1](output);

CodePudding user response:

I think the problem is because you initialize.

useOutput(outputId, id, flowName)[1](output);

inside a function and this is not possible inside a function you need to initialize inside a componenet

  • Related