05-react原理-setState-组件更新机制-组件性能优化

news/2024/7/15 20:31:12 标签: react.js, 性能优化, javascript

setState

更新数据

  • setState() 是异步更新数据的
  • 注意:使用该语法时,后面的 setState() 不要依赖于前面的 setState()
1. 当你调用 setState 的时候,React.js 并不会马上修改 state (为什么)
2. 而是把这个对象放到一个更新队列里面
3. 稍后才会从队列当中把新的状态提取出来合并到 state 当中,然后再触发组件更新。
  • 可以多次调用 setState() ,只会触发一次重新渲染
this.state = { count: 1 }
this.setState({
	count: this.state.count + 1
})
console.log(this.state.count) // 1

在使用 React.js 的时候,并不需要担心多次进行 setState 会带来性能问题。

推荐语法

  • 推荐:使用 setState((preState) => {}) 语法

  • 参数preState: React.js 会把上一个 setState 的结果传入这个函数

this.setState((preState) => {
    return {
    	count: preState.count + 1
    }
})
console.log(this.state.count) // 1

这种语法依旧是异步的,但是state可以获取到最新的状态,适用于需要调用多次setState

第二个参数

  • 场景:在状态更新(页面完成重新渲染)后立即执行某个操作
  • 语法:setState(updater[, callback])
this.setState(
	(state) => ({}),
	() => {console.log('这个回调函数会在状态更新后立即执行')}
)
this.setState(
	(state, props) => {},
	() => {
		document.title = '更新state后的标题:' + this.state.count
	}
)

组件更新机制

  • setState() 的两个作用: 1. 修改 state 2. 更新组件(UI)
  • 过程:父组件重新渲染时,也会重新渲染子组件。但只会渲染当前组件子树(当前组件及其所有子组件)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RYgEvsNe-1642685384234)(images/组件更新.png)]

组件性能优化

  1. 功能第一
  2. 性能优化

减轻state

  • 减轻 state:只存储跟组件渲染相关的数据(比如:count / 列表数据 / loading 等)
  • 注意:不用做渲染的数据不要放在 state 中,比如定时器 id等
  • 对于这种需要在多个方法中用到的数据,应该直接放在 this 中
    • this.xxx = ‘bbb’
    • this.xxx
class Hello extends Component {
    componentDidMount() {
        // timerId存储到this中,而不是state中
        this.timerId = setInterval(() => {}, 2000)
    }
    componentWillUnmount() {
    	clearInterval(this.timerId)
    }
    render() {}
}

vue中不要把和渲染无关的数据放到data中

避免不必要的重新渲染

  • 组件更新机制:父组件更新会引起子组件也被更新,这种思路很清晰

  • 问题:子组件没有任何变化时也会重新渲染 (接收到的props没有发生任何的改变)

  • 如何避免不必要的重新渲染呢?

  • 解决方式:使用钩子函数 shouldComponentUpdate(nextProps, nextState)

  • 作用:通过返回值决定该组件是否重新渲染,返回 true 表示重新渲染,false 表示不重新渲染

  • 触发时机:更新阶段的钩子函数,组件重新渲染前执行 (shouldComponentUpdate => render)

class Hello extends Component {
    shouldComponentUpdate() {
        // 根据条件,决定是否重新渲染组件
        return false
    }
    render() {}
}

案例:随机数

纯组件

  • 纯组件:React.PureComponentReact.Component功能相似
  • 区别:PureComponent 内部自动实现了 shouldComponentUpdate 钩子,不需要手动比较
  • 原理:纯组件内部通过分别 对比 前后两次 props 和 state 的值,来决定是否重新渲染组件
class Hello extends React.PureComponent {
    render() {
        return (
        	<div>纯组件</div>
        )
    }
}

只有在性能优化的时候可能会用到纯组件,不要所有的组件都使用纯组件,因为纯组件需要消耗性能进行对比

纯组件比较-值类型

  • 说明:纯组件内部的对比是 shallow compare(浅层对比)

  • 对于值类型来说:比较两个值是否相同(直接赋值即可,没有坑)

let number = 0
let newNumber = number
newNumber = 2
console.log(number === newNumber) // false
state = { number: 0 }
setState({
  number: Math.floor(Math.random() * 3)
})
// PureComponent内部对比:
最新的state.number === 上一次的state.number // false,重新渲染组件

纯组件比较-引用类型

  • 说明:纯组件内部的对比是 shallow compare(浅层对比)
  • 对于引用类型来说:只比较对象的引用(地址)是否相同
const obj = { number: 0 }
const newObj = obj
newObj.number = 2
console.log(newObj === obj) // true
state = { obj: { number: 0 } }
// 错误做法
state.obj.number = 2
setState({ obj: state.obj })
// PureComponent内部比较:
最新的state.obj === 上一次的state.obj // true,不重新渲染组件

纯组件的最佳实践:

注意:state 或 props 中属性值为引用类型时,应该创建新数据,不要直接修改原数据!

// 正确!创建新数据
const newObj = {...state.obj, number: 2}
setState({ obj: newObj })
// 正确!创建新数据
// 不要用数组的push / unshift 等直接修改当前数组的的方法
// 而应该用 concat 或 slice 等这些返回新数组的方法
this.setState({
	list: [...this.state.list, {新数据}]
})

te.obj, number: 2}
setState({ obj: newObj })
// 正确!创建新数据
// 不要用数组的push / unshift 等直接修改当前数组的的方法
// 而应该用 concat 或 slice 等这些返回新数组的方法
this.setState({
list: […this.state.list, {新数据}]
})





http://www.niftyadmin.cn/n/1397216.html

相关文章

06-react-组件复用-render-props技术

mixins&#xff08;已废弃&#xff09; https://react.docschina.org/blog/2016/07/13/mixins-considered-harmful.html mixin引入了隐式依赖关系 对于组件中的方法和数据的来源不明确&#xff0c;不容易维护 Mixins 导致名称冲突Mixins 导致滚雪球般的复杂性 render-props技术…

07-hooks基本使用-useState-useEffect-自定义hooks

React Hooks基础 React Hooks 介绍React Hooks 基础 React Hooks 介绍 Hooks 是什么为什么要有 Hooks Hooks 是什么 Hooks&#xff1a;钩子、钓钩、钩住Hooks 是 React v16.8 中的新增功能作用&#xff1a;为函数组件提供状态、生命周期等原本 class 组件中提供的 React 功…

08-hooks进阶-useRef-useContext-React.memo高阶组件

Hooks其他API useRef hook import { useRef } from react<inputclassName"new-todo"placeholder"What needs to be done?"autoFocusonKeyUp{onKeyUp}ref{inputRef}/>const App () > {const [color, setColor] useState(red)return (// 用Con…

redux课程

课程说明 目的&#xff1a;为React移动端项目做支撑&#xff1a;redux、redux-thunk、react-redux&#xff08;useDispatch、useSelector &#xff09;、redux-devtools-extension 内容顺序&#xff08;课程目标&#xff09;&#xff1a; redux单独使用react-redux 结合reac…

01-TypeScript 介绍-TypeScript常用类型

TypeScript TypeScript 介绍TypeScript 初体验TypeScript 常用类型TypeScript 高级类型TypeScript 类型声明文件在 React 中使用 TypeScript TypeScript 介绍 TS 官方文档TS 中文参考 - 不再维护 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q…

vue2快速生成代码片段

vue2快速生成代码片段 {// Place your snippets for vue here. Each snippet is defined under a snippet name and has a prefix, body and // description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible varia…

ts文件引入外部资源报错问题

ts中import图片 webpacktypescript项目中如下引入图片会报错(提示找不到该模块)&#xff1a; import xxx from "/imgs/KingLeague/appointment-btn.png"; import xxx from "/imgs/KingLeague/game-info.png";解决&#xff1a;添加图片模块声明文件 如下…

格式化千分位

格式化千分位 numFormat(value) {return Number(value).toLocaleString();// 原生js// let len value.length;// if (len < 3) {// return value;// }// let r len % 3;// value // r > 0// ? value.slice(0, r) // , // value// .slice…