React hooks:将组件作为函数调用与作为元素渲染

IT技术 javascript reactjs react-hooks
2021-04-22 20:37:02

假设我们有组件:

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

我经常遇到这样的代码,其中有人在渲染中将 react 组件称为函数

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

vs将其渲染为元素

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

在 React 钩子中,将组件作为函数调用有哪些可能的缺点


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

1个回答

以下是将组件作为函数调用与将其渲染为元素的一些含义。

  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. 对帐可能无法按预期进行

当您将 react 组件渲染为 react 元素<TestB/>,然后在下一次渲染时渲染一些不同的组件<TestC/>而不是它(在组件层次结构中的同一位置),由于协调算法(并且由于组件类型已更改),react 将卸载<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已呈现,但输入显示的值与您之前键入的值相同 - 当您呈现不同的组件时,这可能不是您想要的。发生这种情况是因为react协调算法无法检测到我们移动到了不同的组件(从TestBTestC)并且没有从 DOM 中删除以前的输入实例。

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