首页 > 解决方案 > 在保持引用相等的同时在 react 中传播 props

问题描述

想象一下,我有一个动态生成组件的一些道具的函数,我想一次将它们全部传递出去,而不需要明确说明该函数可以生成的每个道具。通常您可以使用扩展运算符来执行此操作,但扩展运算符的问题是它每次都创建一个新对象。这意味着(如果我理解正确的话)在React Reconciliation期间,组件每次都会有新的道具并且每次都会重新渲染,即使函数生成的道具是相同的。

这是一个具体的例子:

const generateProps = () => ({foo: 'bar'});

const ParentComponent = () => ({
   const someProps = generateProps();

   return (
      <SomeComponent><ChildComponent {...someProps} otherProp='hello world'/></SomeComponent>
   )
})

这里 ChildComponent 每次ParentComponent都会渲染(对吗?)。我知道您可以做的一件事是ChildComponent用 a包装React.memo并对道具进行更深入的比较(将自定义比较函数传递给它),但是如果您无法控制ChildComponent呢?你是不是被逼得直言不讳?或者我不正确并且ChildComponent不会在这个例子中重新渲染(假设ChildComponent只是消耗道具并且不使用任何上下文或任何东西)。

谢谢!

标签: javascriptreactjs

解决方案


你错了。和解不看道具。它主要看组件类型,例如

如果在一个渲染中渲染

<Comp1/>

并在下一次渲染时,在组件树的同一位置渲染:

<Comp2/>

它将卸载Comp1和安装Comp2,因为组件的类型不同。如果组件类型相同,它将更新现有的。还有一些详细信息,但您可以自己检查。

此外,如果您使用 ,默认情况下也会以浅层方式比较道具React.memo,因此如果在一个渲染中您通过

let y = {a:1,b:2};
....
<Comp1 {...y}/>

在下一次渲染中你通过

let x = {a:1,b:2};
...
<Comp1 {...x}/>

默认比较React.memo会假设 props 没有改变,因为ab具有相同的值。您可以在此处验证,单击div 不会重新渲染Test组件:

 

let Test = React.memo(props => {
  console.log(props);
  return <div>{props.a}</div>;
});

function App() {
  let [state, setState] = React.useState({ a: 123 });
  return (
    <div
      onClick={() => {
        setState({ a: 123 });
      }}
    >
      <h1>Hello StackBlitz!</h1>
      <Test {...state} />
      <p>Start editing to see some magic happen :)</p>
    </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>


推荐阅读