请考虑以下内容:
function Welcome(props) {
return <h1>Hello World</h1>;
}
ReactDOM.render(<Welcome />, document.getElementById('root'));
// React.createElement(Welcome, null)
通过直接调用该功能而不是使用JSX可以实现相同的目的
ReactDOM.render(Welcome(), document.getElementById('root'));
现在我不建议您应该执行此操作,但是我已经看到组件多次以这种方式调用,即
<div>
{SomeComponentOrJSX()}
</div>
它有效。
但是,当您尝试使用钩子时,它会崩溃:
function Counter() {
const [count, setCount] = React.useState(0);
return (
<>
<h1>{count}</h1>
<button onClick={() => setCount(x => x + 1)}>Increment</button>
</>
)
}
这仅在使用React.createElement(Counter, null)
或<Counter />
渲染时才有效
// Works
ReactDOM.render(<Counter />, document.getElementById('root'));
如果您直接调用该函数,将无法正常工作
// Does not work
ReactDOM.render(Counter(), document.getElementById('root'));
它提供的错误是臭名昭著的
Invalid hook call. Hooks can only be called inside of the body of a function component.
这是为什么?
这里的简单答案是不这样做。同意但是,我想更深入地探讨为什么在这种情况下失败了。
我曾经认为React组件只是函数定义,但现在我不确定。因此,对我来说,React组件不仅是定义,而且是使用React.createElement()
答案 0 :(得分:0)
您可能知道,例如<Hello />
转换为React.createElement(Hello, null);
,然后React.createElement
返回一个React知道如何管理的魔术对象(因此,任何React.createElement
调用我们都可以称其为“组件边界” “)。
React会严格跟踪组件边界(请注意,挂钩规则仅在组件边界内起作用)。钩子(就像类组件的生命周期方法一样!)是在React的渲染阶段发生的魔术。如果直接调用Hello()
,则意味着您正在颠覆组件的生命周期,因此,钩子失去了魔力,一切都破了。 (对于类组件,您可以执行(new ClassComponent(someProps)).render()
来执行相同的操作。)