云计算百科
云计算领域专业知识百科平台

父组件setState,子组件为何仍重渲染?

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}

import React,{Component} from 'react';
import './index.css';

export default class Demo extends Component{
state = {
count: 100,
}
render(){
console.log('父组件渲染');

return (
<div className="father">
<h1>我是父组件</h1>
<p className="count">当前计数: {this.state.count}</p>
<button onClick={() => this.setState({count: this.state.count + 1})}>增加</button>
<Child count={this.state.count} />
</div>
)
}
}

class Child extends Component{
render(){
console.log('子组件渲染');

return (
<div className="child">
<h1>我是子组件</h1>
<p className="count">当前计数: {this.props.count}</p>
</div>
)
}
}

以上代码当初次渲染时,后台打印

当渲染到父组件时,执行render,打印;执行到<Child count={this.state.count} /> 时,再去执行子组件中的render,打印。这是完全正常的流程。

当父组件执行<button onClick={() => this.setState({count: this.state.count + 1})}>增加</button> 时,父组件的状态发生改变,触发render,打印,进而子组件也会触发render

那当我不向子组件传递任何值,当我执行父组件中的改变count的方法时,两个组件会都打印吗?

import React,{Component} from 'react';
import './index.css';

export default class Demo extends Component{
state = {
count: 100,
}
render(){
console.log('父组件渲染');

return (
<div className="father">
<h1>我是父组件</h1>
<p className="count">当前计数: {this.state.count}</p>
<button onClick={() => this.setState({count: this.state.count + 1})}>增加</button>
<Child />
</div>
)
}
}

class Child extends Component{
render(){
console.log('子组件渲染');

return (
<div className="child">
<h1>我是子组件</h1>
{/* <p className="count">当前计数: {this.props.count}</p> */}
</div>
)
}
}

结果就是,子组件照样会执行render,重新进行渲染。而且当父组件执行 this.setState({}) 照样会出现相同的效果

子组件我只是想展示一下,只是父组件的状态改变了,他执行render完全没有问题,但是子组件再重新渲染就有点耗性能了。

Component的2个问题

1、只要执行setState(),即使不改变状态数据,组件也会重新render(),效率低

2、只当前组件重新render(),就会重新render子组件,纵使子组件没有用到父组件的任何数据

效率高的做法

只有当前组件的state或props数据发生改变时才重新render()

原因

Component中的shouldComponentUpdate()总是返回true

解决方法一

重写shouldComponentUpdate方法,比较新旧state或props数据,如果有变化参返回true,如果没有则返回false

import React,{Component} from 'react';
import './index.css';

export default class Demo extends Component{
state = {
count: 100,
}

shouldComponentUpdate(nextProps, nextState){
//nextProps: 下一个 props
//nextState: 下一个 state
//返回值: true 表示组件需要重新渲染,false 表示不需要重新渲染
console.log(nextProps, nextState);
//如果下一个 props 或下一个 state 与当前 props 或当前 state 相同,返回 false
//如果下一个 props 或下一个 state 与当前 props 或当前 state 不同,返回 true
if(nextState.count !== this.state.count){
return true;
}
return false;
// return nextState.count !== this.state.count;
}

render(){
console.log('父组件渲染');

return (
<div className="father">
<h1>我是父组件</h1>
<p className="count">当前计数: {this.state.count}</p>
<button onClick={() => this.setState({ count: this.state.count + 100 })}>增加</button>
{/* <Child /> */}
</div>
)
}
}

// class Child extends Component{
// render(){
// console.log('子组件渲染');

// return (
// <div className="child">
// <h1>我是子组件</h1>
// {/* <p className="count">当前计数: {this.props.count}</p> */}
// </div>
// )
// }
// }

当父组件执行方法,改变状态值,也触发render,完全正确。

当执行 this.setState({})呢?

<button onClick={() => this.setState({})}>增加</button>

父组件的状态在前后都没有发生变化,自然不会重新render,达到了提升效率的目的。

同理子组件也可以这样做

import React,{Component} from 'react';
import './index.css';

export default class Demo extends Component{
state = {
count: 100,
}

shouldComponentUpdate(nextProps, nextState){
//nextProps: 下一个 props
//nextState: 下一个 state
//返回值: true 表示组件需要重新渲染,false 表示不需要重新渲染
console.log(nextProps, nextState);
//如果下一个 props 或下一个 state 与当前 props 或当前 state 相同,返回 false
//如果下一个 props 或下一个 state 与当前 props 或当前 state 不同,返回 true
if(nextState.count !== this.state.count){
return true;
}
return false;
// return nextState.count !== this.state.count;
}

render(){
console.log('父组件渲染');

return (
<div className="father">
<h1>我是父组件</h1>
<p className="count">当前计数: {this.state.count}</p>
<button onClick={() => this.setState({ count: this.state.count + 100 })}>增加</button>
<Child count={this.state.count} />
</div>
)
}
}

class Child extends Component{
shouldComponentUpdate(nextProps, nextState){
//nextProps: 下一个 props
//nextState: 下一个 state
//返回值: true 表示组件需要重新渲染,false 表示不需要重新渲染
if(nextProps.count !== this.props.count){
return true;
}
return false;
// return nextState.count !== this.state.count;
}
render(){
console.log('子组件渲染');

return (
<div className="child">
<h1>我是子组件</h1>
<p className="count">当前计数: {this.props.count}</p>
</div>
)
}
}

注意的是,当父组件执行 this.setState({}) 或者不给子组件传递值 <Child />,子组件都不会更新值的。

特别注意

import React,{Component} from 'react';
import './index.css';

export default class Demo extends Component{
state = {
count: 100,
stu:['张三','李四','王五']
}

shouldComponentUpdate(nextProps, nextState){
//nextProps: 下一个 props
//nextState: 下一个 state
//返回值: true 表示组件需要重新渲染,false 表示不需要重新渲染
console.log(nextProps, nextState);
//如果下一个 props 或下一个 state 与当前 props 或当前 state 相同,返回 false
//如果下一个 props 或下一个 state 与当前 props 或当前 state 不同,返回 true
if(nextState.count !== this.state.count){
return true;
}
if(nextState.stu !== this.state.stu){
return true;
}
return false;
// return nextState.count !== this.state.count;
}
addStu(){
const {stu} = this.state;
stu.push('赵六');
this.setState({
stu
})
}

render(){
console.log('父组件渲染');

return (
<div className="father">
<h1>我是父组件</h1>
<p className="count">当前计数: {this.state.count}</p>
<p className="stu">当前学生: {this.state.stu.join('、')}</p>
<button onClick={() => this.setState({ count: this.state.count + 100 })}>增加</button>
<button onClick={() => this.addStu()}>增加学生</button>
</div>
)
}
}

addStu(){
const {stu} = this.state;
stu.push('赵六');
this.setState({
stu
})
}

if(nextState.stu !== this.state.stu){
return true;
}

是触发不了更新的,因为结构出来的stu虽然值变了,但是shouldComponentUpdate判断中nextState.stu和this.state.stu的地址值是前后相同的,进而不会触发render,即便nextState在变化,

要想解决这个麻烦可以这样解决

addStu(){
this.setState({
stu: […this.state.stu, '赵六']
})
}

类似push和shift的操作需要下!!!

单独写

if(nextState.stu.join(',') !== this.state.stu.join(',')){
return true;
}

也是解决不了的

解决方法二

使用 PureComponent代替Component来让组件继承,它重写了shouldComponentUpdate(),只有state和props数据有变化才返回true

注意

只是进行state和props数据的试比较,如果只是数据对象内部数据变了,返回false

不要直接修改数据,而是产生新数据

赞(0)
未经允许不得转载:网硕互联帮助中心 » 父组件setState,子组件为何仍重渲染?
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!