反应:当父组件重新渲染时,孩子总是会重新渲染吗?

Gab*_*est 15 javascript reactjs higher-order-components

据我所知,如果父母组成部分重新出现,那么除非他们实施,否则其所有子女都将会重新投降shouldComponentUpdate().我做了一个例子,这似乎不是真的.

我有3个部分组成:<DynamicParent/>,<StaticParent/><Child/>.该<Parent/>组件负责渲染<Child/>,但以不同的方式做到这一点.

<StaticParent/>渲染函数静态地声明<Child/>运行前,如下所示:

 <StaticParent>
    <Child />
 </StaticParent>
Run Code Online (Sandbox Code Playgroud)

虽然<DynamicParent/>句柄<Child/>在运行时动态接收和呈现,如下所示:

 <DynamicParent>
    { this.props.children }
 </DynamicParent>
Run Code Online (Sandbox Code Playgroud)

两者都有<DynamicParent/>并且<StaticParent/>onClick听众改变他们的状态并在点击时重新渲染.我注意到,点击<StaticParent/>它时都会<Child/>被重新渲染.但是当我点击时<DynamicParent/>,只有父和NOT <Child/>被重新渲染.

<Child/>是一个没有的功能组件,shouldComponentUpdate()所以我不明白它为什么不重新渲染.有人可以解释为什么会这样吗?我在与此用例相关的文档中找不到任何内容.

SrT*_*son 15

我将发布你的实际代码用于上下文:

class Application extends React.Component {
  render() {
    return (
      <div>
        {/* 
          Clicking this component only logs 
          the parents render function 
        */}
        <DynamicParent>
          <Child />
        </DynamicParent>

        {/* 
          Clicking this component logs both the 
          parents and child render functions 
        */}
        <StaticParent />
      </div>
    );
  }
}

class DynamicParent extends React.Component {
  state = { x: false };
  render() {
    console.log("DynamicParent");
    return (
      <div onClick={() => this.setState({ x: !this.state.x })}>
        {this.props.children}
      </div>
    );
  }
}

class StaticParent extends React.Component {
  state = { x: false };
  render() {
    console.log("StaticParent");
    return (
      <div onClick={() => this.setState({ x: !this.state.x })}>
        <Child />
      </div>
    );
  }
}

function Child(props) {
  console.log("child");
  return <div>Child Texts</div>;
}
Run Code Online (Sandbox Code Playgroud)

在Application渲染中编写此代码时:

<StaticParent />
Run Code Online (Sandbox Code Playgroud)

提出的是:

 <div onClick={() => this.setState({ x: !this.state.x })}>
    <Child />
 </div>
Run Code Online (Sandbox Code Playgroud)

而实际上,(大致)会发生什么:

function StaticParent(props) {
  return React.createElement(
    "div",
    { onClick: () => this.setState({ x: !this.state.x }) },
    React.createElement(Child, null)
  );
}

React.createElement(StaticParent, null);
Run Code Online (Sandbox Code Playgroud)

当您像这样渲染DynamicParent时:

<DynamicParent>
    <Child />
</DynamicParent>
Run Code Online (Sandbox Code Playgroud)

这就是实际发生的事情(粗略地说)

function DynamicParent(props) {
    return React.createElement(
        "div",
        { 
            onClick: () => this.setState({ x: !this.state.x }), 
            children: props.children 
        }
    );
}

React.createElement(
      DynamicParent,
      { children: React.createElement(Child, null) },
);
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,这都是孩子:

function Child(props) {
    return React.createElement("div", props, "Child Text");
}
Run Code Online (Sandbox Code Playgroud)

这是什么意思?好吧,在您的StaticParent组件中,React.createElement(Child, null)每次调用StaticParent的render方法时都会调用它.在DynamicParent情况下,Child被创建一次并作为prop传递.而且由于它React.createElement是一个纯粹的功能,所以它可能会在某处为性能而备忘.

什么会使Child的渲染在DynamicParent案例中再次运行是Child的道具的变化.例如,如果将父级的状态用作Child的prop,则会在两种情况下触发重新呈现.

我真的希望丹·阿布拉莫夫没有出现在评论中,以摒弃这个答案,这是一种痛苦的写作(但很有趣)


Xle*_*lee 8

这主要是因为你有两个不同的“孩子”。

  • this.props.children
  • <Child/>

它们不是一回事,第一个是从prop传递下来的Application -> DynamicParent,而第二个是在 中Component渲染的StaticParent,它们具有单独的渲染/生命周期。

您包含的示例

class Application extends React.Component {
  render() {
    return (
      <div>
        {/* 
          Clicking this component only logs 
          the parents render function 
        */}
        <DynamicParent>
          <Child />
        </DynamicParent>

        {/* 
          Clicking this component logs both the 
          parents and child render functions 
        */}
        <StaticParent />
      </div>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

字面上等同于:

class Application extends React.Component {
  render() {
    // If you want <Child/> to re-render here
    // you need to `setState` for this Application component.
    const childEl = <Child />;
    return (
      <div>
        {/* 
          Clicking this component only logs 
          the parents render function 
        */}
        <DynamicParent>
          {childEl}
        </DynamicParent>

        {/* 
          Clicking this component logs both the 
          parents and child render functions 
        */}
        <StaticParent />
      </div>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)