假设我们有一个组件:
let Component = (props)=><div>Hi</div>;
我有时会遇到代码中有人调用react组件作为函数在render:
const App = () => (
<div> {Component()} </div>
)
vs显示为元素
const App = () => (
<div> <Component/> </div>
)
在react钩子中,如果我调用组件作为函数,会出现什么问题?
有一个类似的问题,但它不是专门针对钩子的——那个问题更多的是关于性能的。
如果将component作为function调用而不是将其呈现为element,则可能会发生以下情况。
- 可能违反钩子规则
当你调用一个组件作为一个函数(参见下面的TestB()
),并且它在里面包含钩子的用法,在这种情况下,react认为里面的钩子属于父组件。现在,如果你有条件地渲染组件(TestB()
),你将违反钩子的规则之一。检查下面的例子,单击重新呈现按钮查看错误:
错误:呈现的钩子比预期的少。这可能是由于意外提前返回语句。
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/>
然后在接下来渲染呈现不同的组件<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
到TestC
),并且没有从DOM中删除以前的输入实例。
现在将这些组件呈现为元素(<TestB/>
和<TestC/>
),以查看差异。