Uncaught (in promise) Error: Invalid hook call. - SPECIAL CASE

Uncaught (in promise) Error: Invalid hook call. - SPECIAL CASE

我知道不能从 React 函数式组件以外的函数调用 hooks,这有点不同。

我创建了一些需要使用 hooks 的 utility/service 类型的函数。

// somewhere in services files...
const utilNavTo = (route) => {
    const navigate = useNavigate();
    ...
};

// somewhere in components for screens...
const MyScreen = () => {
   ...
   if(something){
      utilNavTo('/somewhere');
   }
   ...
};

// the main app is created with <App /> not App, so that should not be the reason of error
ReactDOM.render(<App />, document.getElementById("root"));

// also App is fully defined with routes having <MyScreen /> defined properly...

当在 React 功能组件中使用这样的函数时,我收到此错误:

Uncaught (in promise) 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

如果我从 React 功能组件调用 hook 并将其传递给实用程序函数,它工作得很好。

有没有什么方法可以在不将钩子作为参数传递的情况下完成这项工作? 我想只有当效用函数本身不是从功能组件调用时它才会失败。

问题

这里的问题是代码在回调函数中有条件地调用 useNavigate。这打破了 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. By following this rule, you ensure that Hooks are called in the same order each time a component renders.

解决方案

utilNavTo 转换成一个自定义 React 挂钩,returns 一个函数供组件使用。 hook应该在函数组件体中调用。

示例:

// somewhere in services files...
const useUtilNavTo = () => {
  const navigate = useNavigate();

  const utilNavTo = (route) => {
    ...
  };

  return utilNavTo;
};

...

// somewhere in components for screens...
const MyScreen = () => {
  const utilNavTo = useUtilNavTo();

  ...

  if(something){
    utilNavTo('/somewhere');
  }

  ...
};