this.props.children不会在父状态更改时重新呈现

时间:2017-11-30 06:47:15

标签: reactjs

我有一段代码

import React, {Component} from 'react';

class App extends Component {
  render() {
    return (
      <Container>
        <Child/>
      </Container>
    )
  }
}

class Container extends Component {
  render() {
    console.log('Container render');
    return (
      <div onClick={() => this.setState({})}>
        {this.props.children}
      </div>
    )
  }
}

class Child extends Component {
  render() {
    console.log('Child render');
    return <h1>Hi</h1>
  }
}

export default App;

点击&#39;嗨&#39; msg,只有Container组件会重新呈现,但不会重新呈现Child组件。

为什么在Child状态更改时不会重新呈现Container组件?

我认为,由于它是Container组件的属性,它不会发生,但仍然this.props.child被评估为JSX中的Child组件,所以不确定。

<div onClick={() => this.setState({})}>
  {this.props.children}
</div>

完整示例https://codesandbox.io/s/529lq0rv2n(检查控制台日志)

3 个答案:

答案 0 :(得分:3)

这个问题已经很老了,但是由于您似乎没有得到满意的答案,因此我也会试一试。

您自己观察到的变化

// Scenario A

<div onClick={() => this.setState({})}>
  {this.props.children}
</div>

// Scenario B

<div onClick={() => this.setState({})}>
  <Child />
</div>

实际上将以

结尾
  

容器渲染
  儿童渲染

在控制台中,每次单击。

现在,为您报价

  

据我所知,如果触发setState(),则渲染功能   容器组件被调用,所有子元素都应为   重新渲染。

您似乎非常了解这里发生的事情。

到目前为止,您是正确的,因为执行了Container的{​​{1}},所以从它返回的组件必须调用它们自己的render方法。

现在,正如您还说的那样,

render

从本质上讲,您从以上获得的内容只是一个<Child /> // is equal to React.createElement(Child, {/*props*/}, /*children*/) ,描述了屏幕上显示的内容, React Element

关键是要了解在以上每种情况下object执行的时间。

所以让我们看看发生了什么

React.createElement(Child, {/*props*/}, /*children*/)

您可以像这样重写class App extends Component { render() { return ( <Container> <Child/> </Container> ) } } class Container extends Component { render() { console.log('Container render'); return ( <div onClick={() => this.setState({})}> {this.props.children} </div> ) } } class Child extends Component { render() { console.log('Child render'); return <h1>Hi</h1> } } 的返回值:

App

您还可以像这样重写<Container> <Child/> </Container> // is equal to React.createElement( Container, {}, React.createElement( Child, {}, {} ) ) // which is equal to a React Element object, something like { type: Container, props: { children: { type: Child, // | props: {}, // +---> Take note of this object here children: {} // | } } } 的返回值:

Container

现在,<div onClick={() => this.setState({})}> {this.props.children} </div> // is equal to React.createElement( 'div', {onClick: () => this.setState({})}, this.props.children ) // which is equal to React Element { type: 'div', props: { children: this.props.children } } this.props.children返回的React Element中包含的内容相同:

App

准确地说,这两件事完全相同,这意味着在两种情况下,它们在内存中都是完全相同的。

现在,无论{ type: Child, props: {}, children: {} } 被重新渲染多少次,因为它的Container在渲染之间总是参照相同的(因为React Element是在children级别创建的)并且没有理由进行更改),它们不会被重新渲染。

简而言之,如果引用(App)等于上一个渲染中的React元素,React不会再次渲染它。

现在,如果要更改===,您将具有:

Container

但是在这种情况下,如果您要重新渲染<div onClick={() => this.setState({})}> <Child /> </div> // is equal to React.createElement( 'div', {onClick: () => this.setState({})}, React.createElement( Child, {}, {} ) ) // which is equal to { type: 'div', props: { children: { type: Child, props: {}, children: {} } } } ,它将不得不重新执行

Container

针对每个渲染器。这将导致React元素在渲染之间的引用存在差异,因此即使最终结果相同,React也会实际上也重新渲染React.createElement( Child, {}, {} ) 组件。

Reference

答案 1 :(得分:1)

<Child />组件未重新渲染,因为道具未更改。 React使用Virtual DOM的概念,它是组件及其数据的表示。

如果组件的道具未更改,则不会重新渲染组件。这就是让React保持快速的原因。

在您的示例中,没有向Child发送的道具,因此永远不会重新渲染。如果你想每次都重新渲染(为什么会这样?),你可以使用一个纯函数

const Child = () => <h1>Hi</h1>;

答案 2 :(得分:1)

将容器组件中的{this.props.children}更改为<Child />,(现在您可以从App组件中删除<Child />)。

如果您点击div,您将在控制台中同时获得“儿童渲染”和“容器渲染”。

(在这个示例中,您的孩子是静态组件。然后重新呈现没有意义。)