我有一段代码
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(检查控制台日志)
答案 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,
{},
{}
)
组件。
答案 1 :(得分:1)
<Child />
组件未重新渲染,因为道具未更改。 React使用Virtual DOM的概念,它是组件及其数据的表示。
如果组件的道具未更改,则不会重新渲染组件。这就是让React保持快速的原因。
在您的示例中,没有向Child
发送的道具,因此永远不会重新渲染。如果你想每次都重新渲染(为什么会这样?),你可以使用一个纯函数
const Child = () => <h1>Hi</h1>;
答案 2 :(得分:1)
将容器组件中的{this.props.children}
更改为<Child />
,(现在您可以从App组件中删除<Child />
)。
如果您点击div,您将在控制台中同时获得“儿童渲染”和“容器渲染”。
(在这个示例中,您的孩子是静态组件。然后重新呈现没有意义。)