发布时间:2024-08-27 12:01
前言
博主主页👉🏻蜡笔雏田学代码
专栏链接👉🏻React专栏
接上一篇文章react的扩展知识,今天来学习React的另外一些扩展知识
感兴趣的小伙伴一起来看看吧~🤞
问题1:
只要执行setState(),即使不改变状态数据 ( this.setState({})),组件也会重新render() ==> 效率低
问题2:
只要当前组件重新render(),就会自动重新render子组件,纵使子组件没有用到父组件的任何数据 ==> 效率低
效率高的做法
只有
当组件的state或props数据发生改变
时才重新render()
原因
Component中的shouldComponentUpdate()总是返回true
问题1:
只要执行setState(),即使不改变状态数据 ( this.setState({})),组件也会重新render() ==> 效率低
比较新旧state或props数据,如果有变化才返回true,如果没有返回false
export default class Parent extends Component {
state = { carName: '奔驰' }
changeCar = () => {
this.setState({})
}
shouldComponentUpdate(nextProps, nextState) {
console.log(this.props, this.state) //目前的props和state
console.log(nextProps, nextState) //接下来要变化的目标props,目标state
if (this.state.carName === nextState.carName) return false
else return true
}
render() {
console.log('parent--render')
return (
<div className='parent'>
<h3>我是Parent组件</h3>
<span>我的车名字是:{this.state.carName}</span><br />
<button onClick={this.changeCar}>点我换车</button>
</div>
)
}
}
效果
此时在点击完按钮之后,当前组件的state状态并没有发生变化,所以shouldComponentUpdate()里的if判断返回的是false,进而不会引起组件的重新渲染,不会调用render。
问题2
和问题1一样重写shouldComponentUpdate()方法
问题2: 只要当前组件重新render(),就会自动重新render子组件,纵使子组件没有用到父组件的任何数据 ==> 效率低
import React, { Component } from 'react'
import './index.css'
export default class Parent extends Component {
state = { carName: '奔驰' }
changeCar = () => {
this.setState({ carName: '宝马' })
}
shouldComponentUpdate(nextProps, nextState) {
// console.log(this.props, this.state) //目前的props和state
// console.log(nextProps, nextState) //接下来要变化的目标props,目标state
if (this.state.carName === nextState.carName) return false
else return true
}
render() {
console.log('parent--render')
return (
<div className='parent'>
<h3>我是Parent组件</h3>
<span>我的车名字是:{this.state.carName}</span><br />
<button onClick={this.changeCar}>点我换车</button>
<Child carName='奥拓' />
</div>
)
}
}
class Child extends Component {
shouldComponentUpdate(nextProps, nextState) {
console.log(this.props, this.state) //目前的props和state
console.log(nextProps, nextState) //接下来要变化的目标props,目标state
if (this.props.carName === nextProps.carName) return false
else return true
}
render() {
console.log('child--render')
return (
<div className='child'>
<h3>我是Child组件</h3>
<span>我接到的车是:{this.props.carName}</span>
</div>
)
}
}
效果
此时子组件接收到的props数据是固定不变的 ( < < <Child carName=‘奥拓’ />) ,所以子组件里的shouldComponentUpdate()里的if判断返回的是false,进而不会引起子组件的重新渲染,不会调用render。
当state状态里有多组数据,那么shouldComponentUpdate()里就要进行多个判断,这样显然在真正开发里是不可行的。所以我们可以不用手动写shouldComponentUpdate()方法, 使用PureComponent, 可以重写shouldComponentUpdate()里的逻辑, 只有state或props数据有变化才返回true。(项目中一般使用PureComponent来优化)
import React, { PureComponent } from 'react'
...
export default class Parent extends PureComponent{}
...
class Child extends PureComponent{}
...
注意! 🔥 PureComponent只是进行state和props数据的浅比较
,如果只是数据对象内部数据变了,返回false。 不要直接修改state数据, 而是要产生新数据
//错误写法
const obj = this.state
obj.carName = '宝马'
this.setState(obj)
这样修改数据,只是
对原state对象内的值做了修改
,但是对象的引用地址没变
!!
在PureComponent看来,引用地址没变时,组件内部的shouldComponentUpdate返回false,也就不会重新render,数据更新就失败了。
//正确写法
this.setState({ carName: '宝马' })
这样修改数据,就是用一个新对象{ carName: ‘宝马’ }替换了原来的state对象,数据的引用地址变化了,那么PureComponent组件内部的shouldComponentUpdate返回true,组件重新render,数据更新成功。
Vue中:
使用slot插槽技术,也就是通过组件标签体传入结构
<A>
<B/>
</A>
React中:
使用children props: 通过
组件标签体
传入结构使用render props: 通过
组件标签属性
传入结构,而且可以携带数据
,一般用render函数属性
<A>
<B>xxxx</B>
</A>
{this.props.children}
问题: 如果B组件需要A组件内的数据, ==> 做不到
export default class Parent extends Component {
render() {
return (
<div className='parent'>
<h3>我是parent组件</h3>
<A>
<B />
</A>
</div>
)
}
}
class A extends Component {
render() {
console.log(this.props)
return (
<div className='a'>
<h3>我是A组件</h3>
{this.props.children}
</div>
)
}
}
class B extends Component {
render() {
return (
<div className='b'>
<h3>我是B组件</h3>
</div>
)
}
}
效果
<A render={(data) => <C data={data}></C>}></A>
A组件: {this.props.render(内部state数据)}
C组件: 读取A组件传入的数据显示 {this.props.data}
如果在children props写法的基础上, 若要将A组件state身上的name属性传给B组件, 我们就需要使用render props来写:
export default class Parent extends Component {
render() {
return (
<div className='parent'>
<h3>我是parent组件</h3>
<A render={(name) => <B name={name} />} />
</div>
)
}
}
class A extends Component {
state = { name: 'jack' }
render() {
console.log(this.props)
const { name } = this.state
return (
<div className='a'>
<h3>我是A组件</h3>
{this.props.render(name)}
</div>
)
}
}
class B extends Component {
render() {
return (
<div className='b'>
<h3>我是B组件,{this.props.name}</h3>
</div>
)
}
}
效果
错误边界(Error boundary):把错误控制在一定范围内,比如后端返回来的数据类型出错,或者一些其他的错误,我们可以在界面中提示用户一些“网络繁忙请稍后重试”信息,错误边界Error boundary就是用来捕获后代组件错误,渲染出备用页面。
错误边界一般是在容易发生错误的组件的父组件中处理。
只能捕获后代组件生命周期产生的错误,不能捕获自己组件产生的错误和其他组件在合成事件、定时器中产生的错误。
getDerivedStateFromError配合componentDidCatch
export default class Parent extends Component {
state = {
hasError: '' //用于标识子组件是否产生错误
}
// 如果Parent组件的子组件出现了任何的报错,都会调用这个钩子函数,调用的时候传入error错误信息
static getDerivedStateFromError(error) {
console.log(error)
return { hasError: error }// 返回新的state
}
render() {
return (
<div>
<h2>我是Parent组件</h2>
{this.state.hasError ? <h2>当前网络不稳定,请稍后再试</h2> : <Child />}
</div>
)
}
}
// 如果组件在渲染的整个过程中,由于子组件出现了问题,引发一些错误,
//就会调用此函数,用来统计错误,反馈给服务器,用于通知编码人员进行bug的解决
componentDidCatch(error, info) {
// 统计页面的错误。发送请求发送到后台去
console.log(error, info);
}
效果
父子组件:props
兄弟组件:消息订阅-发布、集中式管理
祖孙组件(跨级组件):消息订阅-发布、集中式管理、conText(开发用的少,封装插件用的多)
今天的分享就到这里啦✨ \\textcolor{red}{今天的分享就到这里啦✨} 今天的分享就到这里啦✨
原创不易,还希望各位大佬支持一下 \\textcolor{blue}{原创不易,还希望各位大佬支持一下} 原创不易,还希望各位大佬支持一下
🤞 点赞,你的认可是我创作的动力! \\textcolor{green}{点赞,你的认可是我创作的动力!} 点赞,你的认可是我创作的动力!
⭐️ 收藏,你的青睐是我努力的方向! \\textcolor{green}{收藏,你的青睐是我努力的方向!} 收藏,你的青睐是我努力的方向!
✏️ 评论,你的意见是我进步的财富! \\textcolor{green}{评论,你的意见是我进步的财富!} 评论,你的意见是我进步的财富!
前端经典面试题 | 吊打面试官系列 之 Vue2和Vue3的区别
助力人工智能迈向新阶段,YLearn因果学习开源项目重磅发布!
Springboot 手动分页查询分批批量插入数据的实现流程
cs224w(图机器学习)2021冬季课程学习笔记9 Graph Neural Networks 2: Design Space
Java ArrayList与LinkedList及HashMap容器的用法区别
Notion连接钉钉宜搭:快速解决候选人信息无法自动同步到表单的问题
在linux开发板上编译程序的代码,建立交叉编译环境和在开发板上实现第一个嵌入式Linux应用程序...
南华大学计算机学院足球队,【体育学院】南华大学“新生杯”足球赛圆满落幕...
SAP Commerce Cloud 构建环境和最终运行环境的区别