是否可以将 React.hook 传递给函数?

Is it possible to pass a React.hook to a function?

我可以将 React.hooks 传递给函数并在那里使用它吗?

    const [X, setX] = useState('');

    function  Y(useX){
       useX('string');
    }
    Y(setX)

正如规则所述,hooks 只能在功能组件的顶部调用,不应该有条件地调用,所以虽然从技术上讲你可以将它作为函数的参数传递,但是你需要立即执行函数

所以

const App = () => {
    const [X, setX] = React.useState('x');

    function Y(useX){
       useX('string');
    }

    Y(React.useState);
    
    return <div>Hello {X}</div>
}

ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="app" />

没问题。

但是下面的代码不起作用

const App = () => {
    const [X, setX] = React.useState('x');

    function Y(useX){
       useX('string');
    }
    
    
    return <div>Hello {X} <button onClick={() => {Y(React.useState)}}>Click</button></div>
}

ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="app" />

因此您不应该以这种方式使用它,因为您稍后可能会在函数调用中添加一些语句,因此挂钩不会保留其调用顺序

需要维护 Hooks 调用的顺序,因为 React 依赖于 hooks 调用顺序来维护方法中使用的 hooks 队列并处理所有进一步的更新

Technically if useX is a custom hook, it essentially a function that is invoked from within a component that contains hooks at the top level

在这种情况下,传递的不是钩子而是 setter 函数,钩子限制不适用于 Y(setX)。它不一定位于组件范围内:

function  Y(setX){
  setX('string');
}

const Comp = () => {
  const [X, setX] = useState('');
  Y(setX);
  ...
}

根据使用情况,它可以从记忆中获益,例如,如果 () => Y(setX) 应该作为 prop 传递:

const Comp = () => {
  const [X, setX] = useState('');
  const setY = useCallback(() => Y(setX), []);
  ...
}

使用hooks时,必须遵守一定的hook rules(目前只有两条):

  1. 仅在顶层调用挂钩
  2. 仅从 React 函数调用挂钩

通过尝试将挂钩传递给常规函数您违反了这两个规则。虽然这些规则更多的是惯例,而不是实际限制,并且在某些情况下可能有效(正如该线程中的其他人所提到的)(要么你知道你在哪里以及为什么可以使用它们或者您不小心满足了它们的使用要求) 不建议以这种方式使用它们。例如,一段时间后您可能会忘记您的函数包含一个钩子并且实际上取决于它在何处以及如何声明和使用,并将它四处移动或放入条件中,从而有效地破坏您的应用程序的逻辑。

React 人员想出了专用的 ESlint plugin 非常重要,它旨在在后台分析您的代码并在您接近违反钩子规则时准确警告您。这是确定的方法。

如果您仍然需要从组件中提取一些依赖于钩子的逻辑到一个单独的函数中,请考虑创建一个 custom hook

但是!

在您的示例代码中,您没有将挂钩传递给函数。 React.useState是一个钩子,但是setX它returns不是。 您可以随心所欲地传递它,实际上您是要将它传递给您自定义的常规函数​​或自定义挂钩!