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

时间:2018-04-26 23:06:35

标签: javascript reactjs higher-order-components

据我所知,如果父母组成部分重新渲染,那么除非他们实施Picker.js:11 Uncaught TypeError: _onChange is not a function at onChange (Picker.js:11) at HTMLUnknownElement.callCallback (react-dom.development.js:100) at Object.invokeGuardedCallbackDev (react-dom.development.js:138) at Object.invokeGuardedCallback (react-dom.development.js:187) at Object.invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:201) at executeDispatch (react-dom.development.js:466) at executeDispatchesInOrder (react-dom.development.js:488) at executeDispatchesAndRelease (react-dom.development.js:586) at executeDispatchesAndReleaseTopLevel (react-dom.development.js:597) at forEachAccumulated (react-dom.development.js:567) at runEventsInBatch (react-dom.development.js:728) at runExtractedEventsInBatch (react-dom.development.js:737) at handleTopLevel (react-dom.development.js:4201) at batchedUpdates (react-dom.development.js:12537) at batchedUpdates (react-dom.development.js:1939) at dispatchEvent (react-dom.development.js:4282 ,否则其所有子女都会重新渲染。我made an example,这似乎不是真的。

我有3个组件:shouldComponentUpdate()<DynamicParent/><StaticParent/><Child/>组件负责呈现<Parent/>但以不同方式执行此操作。

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

<Child/>

<StaticParent> <Child /> </StaticParent> 处理在运行时动态接收和呈现<DynamicParent/>,如下所示:

<Child/>

<DynamicParent> { this.props.children } </DynamicParent> <DynamicParent/>都有<StaticParent/>个侦听器来更改其状态并在单击时重新呈现。我注意到,点击onClick后,它和<StaticParent/>都会被重新呈现。但是当我点击<Child/>时,只会重新呈现父级而非<DynamicParent/>

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

4 个答案:

答案 0 :(得分:11)

我会发布您的实际代码以供上下文使用:

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

在Application render中编写此代码时:

<StaticParent />

提供的内容是:

 <div onClick={() => this.setState({ x: !this.state.x })}>
    <Child />
 </div>

实际上,(大致)会发生这样的事情:

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

React.createElement(StaticParent, null);

当您像这样渲染DynamicParent时:

<DynamicParent>
    <Child />
</DynamicParent>

这是实际发生的事情(再次,粗略地说)

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) },
);

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

function Child(props) {
    return React.createElement("div", props, "Child Text");
}

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

在DynamicParent案例中,让孩子的渲染再次运行的是Child's道具的变化。例如,如果父母的状态被用作儿童的道具,则会在两种情况下触发重新渲染。

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

答案 1 :(得分:4)

这主要是因为你有2个不同的孩子&#34;

  • 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>
    );
  }
}

字面意思如下:

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>
    );
  }
}

答案 2 :(得分:1)

作为对SrThompsons的评论,答案是:“在DynamicParent案例中,使Child的渲染再次运行的原因是Child的道具发生了变化。例如,如果将父级的状态用作对Child的道具,则将触发-在两种情况下都呈现。” 因此,如果将道具传递给子组件,则该道具是否会传递给父组件(如果父组件重新渲染,那么它看起来会引起重新渲染(因此,对没有道具的孩子使用React.memo))

“无论您是将组件实现为扩展React.Component的类组件还是功能组件,只要父容器再次渲染,都会再次调用render函数。”请阅读此处以获取更多信息,因为很棒的文章。 https://medium.com/free-code-camp/yeah-hooks-are-good-but-have-you-tried-faster-react-components-e698a8db468c

答案 3 :(得分:-3)

它只会重新渲染已经发生变化的组件。如果子组件上没有任何内容发生更改,则不会重新呈现。