考虑我们有这个示例组件:
function Counter() {
const [count, setCount] = React.useState(0);
return (
<div>
<div> {count} </div>
<button
onClick={() => {
setCount(count + 1);
}}
>
Increase
</button>
</div>
);
}
我有时会遇到一些代码,其中有人在渲染中将反应组件调用为函数:
const App = () => (
<div> {Counter()} </div>
)
vs 将其渲染为元素:
const App = () => (
<div> <Counter/> </div>
)
在react hooks中,是否允许将组件作为函数调用?如果我们这样做会出现什么问题?
似乎有一个问题可以认为与此类似;尽管那不是专门关于钩子的。而且这个问题似乎强调了性能影响。
React docs 不鼓励将组件作为函数调用:
组件只能在 JSX 中使用。不要像平常那样称呼他们 功能。 React 应该调用它。
他们提到的原因之一是:
如果组件包含Hooks,很容易违反Hooks规则 当直接在循环中或有条件地调用组件时。
虽然他们没有详细说明上面的引用,但我认为下面的示例显示了他们可能的含义。
当您将组件作为函数调用并且其中包含钩子的使用时,在这种情况下,React 会认为该函数中的钩子属于父组件。因此,如果您有条件地调用此类组件(就像我们对下面的
TestB()
所做的那样),您将违反钩子的rules之一。点击重新渲染按钮可以看到错误:
错误:渲染的钩子数量少于预期。这可能是由于 意外提前退货声明。
function TestB() {
let [B, setB] = React.useState(0);
return (
<div
onClick={() => {
setB(B + 1);
}}
>
counter B {B}
</div>
);
}
function App() {
let [A, setA] = React.useState(0);
return (
<div>
<button
onClick={() => {
setA(A + 1);
}}
>
re-render
</button>
{/* Conditionally render TestB() */}
{A % 2 == 0 ? TestB() : null}
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
现在您可以使用上面的
<TestB/>
来代替并查看差异。
文档还提到将组件呈现为元素(而不是将其作为函数调用)允许组件类型参与协调。
这意味着,当您将反应组件渲染为反应元素时,例如
<TestB/>
,然后在下一次渲染时,由于协调算法(并且因为组件类型已更改),React 将卸载 <TestC/>
组件(其所有状态都将消失)并安装一个新组件 <TestB/>
。但是,如果您将其称为函数(例如<TestC/>
),则组件类型将不再参与协调,您可能无法获得预期的结果。见下面的例子:
TestB()
function TestB() {
return (
<div
>
<input/>
</div>
);
}
function TestC() {
console.log("TestC")
return (
<div
>
<input/>
</div>
);
}
function App() {
let [A, setA] = React.useState(0);
return (
<div>
<button
onClick={() => {
setA(A + 1);
}}
>
re-render
</button>
{/* Here we are alternating rendering of components */}
{A % 2 == 0 ? TestB() : TestC()}
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById("react")
);
在输入框中输入内容
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
TestC
到 TestB
)并且没有从 DOM 中删除先前的输入实例。
TestC
和
<TestB/>
)以查看差异。将组件渲染为元素的好处文档还提到了将组件渲染为元素的以下好处:
组件不再只是功能。 React 可以通过以下方式增强它们 通过 Hooks 绑定到本地状态等功能 组件在树中的身份。
组件类型参与协调。通过让 React 调用 你的组件,你还告诉它更多关于概念结构的信息 你的树。例如,当您从渲染移动到 页面,React 不会尝试重用它们。
React 可以增强您的用户体验。例如,它可以让 浏览器在组件调用之间做一些工作,以便重新渲染 大组件树不会阻塞主线程。
更好的调试故事。如果组件是一等公民 该库知道,我们可以构建丰富的开发工具 在发展中反省。
更高效的对账。 React 可以准确决定哪个 树中的组件需要重新渲染并跳过那些 不。这使您的应用程序更快、更敏捷。