React hooks:调用组件作为函数,而渲染作为元素



假设我们有一个组件:

let Component = (props)=><div>Hi</div>;

我有时会遇到代码中有人调用react组件作为函数在render:

const App = () => (
<div> {Component()} </div>
)

vs显示为元素

const App = () => (
<div> <Component/> </div>
)

在react钩子中,如果我调用组件作为函数,会出现什么问题?


有一个类似的问题,但它不是专门针对钩子的——那个问题更多的是关于性能的。

如果将component作为function调用而不是将其呈现为element,则可能会发生以下情况。

  1. 可能违反钩子规则

当你调用一个组件作为一个函数(参见下面的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/>来代替,看看有什么不同。

  1. 对账可能无法正常工作

当你渲染组件作为反应的反应元素说<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被渲染了,但是输入显示的值与您之前输入的值相同—这可能不是您想要的,因为您渲染了不同的组件。这是因为反应协调算法无法检测到我们移动到一个不同的组件(从TestBTestC),并且没有从DOM中删除以前的输入实例。

现在将这些组件呈现为元素(<TestB/><TestC/>),以查看差异。

相关内容

  • 没有找到相关文章

最新更新