React hooks:将组件作为函数调用与作为元素渲染 [英] React hooks: call component as function vs render as element

查看:22
本文介绍了React hooks:将组件作为函数调用与作为元素渲染的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们有组件:

let Component = (props)=>

Hi

;

我有时会遇到这样的代码,其中有人在渲染中将反应组件作为函数调用:

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

vs 将其渲染为元素

 const App = () =>(<div><组件/>

)

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


类似的问题,但它是不是专门针对钩子的 - 这个问题更多地是关于性能的.

解决方案

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

  1. 可能违反钩子规则

当你将一个组件作为函数调用(参见下面的TestB())并且它包含内部的钩子使用,在那个case react 认为 函数内的钩子属于 组件.现在,如果您有条件地呈现该组件 (TestB()),您将违反 规则 钩子.检查下面的示例,单击重新渲染按钮查看错误:

<块引用>

错误:呈现的钩子比预期的少.这可能是由意外提前退货声明.

功能测试B(){让 [B, setB] = React.useState(0);返回 (

{设置B(B + 1);}}>计数器 B {B}

);}功能应用(){让 [A, setA] = React.useState(0);返回 (<div><按钮onClick={() =>{设置A(A + 1);}}>重新渲染{/* 有条件地渲染 TestB() */}{A % 2 == 0 ?测试B():空}

);}ReactDOM.render(<应用程序/>,document.getElementById("反应"));

<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>

现在您可以改用 并查看不同之处.

  1. 协调可能无法按预期进行

当你将一个 react 组件渲染为 react 元素时,说 然后在下一次渲染时你渲染​​一些不同的组件 其中(在组件层次结构中的同一位置),由于协调算法(并且由于组件类型已更改),react 将卸载 组件(它的所有状态都将消失)并安装一个新组件 代替.

如果您将其称为函数(例如 TestB()),组件类型将不再参与协调,您可能无法获得预期的结果:

function TestB() {返回 (

);}函数 TestC() {console.log("TestC")返回 (

);}功能应用(){让 [A, setA] = React.useState(0);返回 (<div><按钮onClick={() =>{设置A(A + 1);}}>重新渲染{/* 这里我们交替渲染组件 */}{A % 2 == 0 ?TestB() : TestC()}

);}ReactDOM.render(<应用程序/>,document.getElementById("反应"));

<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>

现在将这些组件渲染为元素()以查看差异.

Say we have component:

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

I have sometimes come across code where someone calls a react component as function in render:

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

vs rendering it as element

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

In react hooks, what are possible drawbacks of calling component as function?


There is similar question but it is not specifically targeted at hooks - also that question is more about performance.

解决方案

Here are some implications of calling component as function vs rendering it as element.

  1. Potential violation of rules of hooks

When you call a component as a function (see TestB() below) and it contains usage of hooks inside it, in that case react thinks the hooks within that function belongs to the parent component. Now if you conditionally render that component (TestB()) you will violate one of the rules of hooks. Check the example below, click the re-render button to see the error:

Error: Rendered fewer hooks than expected. This may be caused by an accidental early return statement.

 
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>

Now you can use <TestB/> instead and see the difference.

  1. Reconciliation might not work as expected

When you render a react component as react element say <TestB/> and then on next render you render some different component <TestC/> instead of it (in the same place in component hierarchy), due to reconciliation algorithm (and since component type has changed), react will unmount <TestB/> component (all its state will be gone) and mount a new component <TestC/> instead.

If you call it as function however (e.g. TestB()), the component type will not participate in reconciliation anymore and you might not get expected results:

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>

  • Type something in the input
  • Now click the re-render button
  • You can see now from the log that component TestC was rendered, but the input shows the same value you typed before - which might not be what you want as you rendered a different component. This happened because reacts reconciliation algorithm couldn't detect that we moved to a different component (from TestB to TestC) and didn't remove previous input instance from DOM.

Render these components as elements now (<TestB/> and <TestC/>) to see the difference.

这篇关于React hooks:将组件作为函数调用与作为元素渲染的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆