赞
踩
旧版本
挂载阶段:componentWillMount - render - componentDidMount
更新阶段:componentWillReceiveProps - shouldComponentUpdate - componentWillUpdate - render - componentDidUpdate
卸载阶段:componentWillUnmount
新版本
挂载阶段:getDerivedStateFromProps - render - componentDidMount
更新阶段:getDerivedStateFromProps - shouldComponentUpdate - render - getSnapShotBeforeUpdate - componentDidUpdate
卸载阶段:componentWillUnmount
父子组件初始化
父组件 constructor
父组件 getDerivedStateFromProps
父组件 render
子组件 constructor
子组件 getDerivedStateFromProps
子组件 render
子组件 componentDidMount
父组件 componentDidMount
子组件修改自身state
子组件 getDerivedStateFromProps
子组件 shouldComponentUpdate
子组件 render
子组件 getSnapShotBeforeUpdate
子组件 componentDidUpdate
父组件修改props
父组件 getDerivedStateFromProps
父组件 shouldComponentUpdate
父组件 render
子组件 getDerivedStateFromProps
子组件 shouldComponentUpdate
子组件 render
子组件 getSnapShotBeforeUpdate
父组件 getSnapShotBeforeUpdate
子组件 componentDidUpdate
父组件 componentDidUpdate
卸载子组件
父组件 getDerivedStateFromProps
父组件 shouldComponentUpdate
父组件 render
父组件 getSnapShotBeforeUpdate
子组件 componentWillUnmount
父组件 componentDidUpdate
https://blog.csdn.net/Dax1_/article/details/126671937
在React中,如果是由React引发的事件处理(比如通过onClick引发的事件处理),调用setState不会同步更新this.state,除此之外的setState调用会同步执行this.state 。所谓“除此之外”,指的是绕过React通过addEventListener直接添加的事件处理函数,还有通过setTimeout/setInterval产生的异步调用。
原因: 在React的setState函数实现中,会根据一个变量isBatchingUpdates判断是直接更新this.state还是放到队列中回头再说,而isBatchingUpdates默认是false,也就表示setState会同步更新this.state,但是,有一个函数batchedUpdates,这个函数会把isBatchingUpdates修改为true,而当React在调用事件处理函数之前就会调用这个batchedUpdates,造成的后果,就是由React控制的事件处理过程setState不会同步更新this.state。
注意: setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。
class Example extends React.Component {
constructor() {
super();
this.state = {
val: 0
};
}
componentDidMount() {
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 1 次 logthis.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 2 次 logsetTimeout(() => {
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 3 次 logthis.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 4 次 log
}, 0);
}render() {
return null;
}
};
输出结果为:0 0 2 3
import { useEffect, useLayoutEffect } from 'react';
export const useCustomLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
useReducer和useState都可以用来管理组件的状态,useReducer将状态和状态的变化统一管理在reducer函数里面,这样对于一些复杂的状态管理会十分方便我们debug,因为它对状态的改变是封闭的。而由于useState返回的setState可以直接在任意地方设置我们状态的值,当我们组件的状态转换逻辑十分复杂时,它将很难debug,因为它是开放的状态管理。
useState情况使用
useReducer情况使用
三者都是避免重复渲染,从而达到性能优化的目的
Memo:
如果你的组件在相同 props 的情况下渲染相同的结果,那么你可以通过将其包装在React.memo中调用,以此通过记忆组件渲染结果的方式来提高组件的性能表现。这意味着在这种情况下,React 将跳过渲染组件的操作并直接复用最近一次渲染的结果。
memo是一个高阶组件。它的功能我们可以这么理解:
被调用时返回传入的组件
每次传入的组件要执行更新时,组件的新props和之前的老props会进行一次浅比较:
结果相等,不触发更新
结果不相等,触发更新,重新渲染
useCallBack和useMemo唯一的区别是:useMemo返回的是传入的回调函数的执行结果,useCallBack返回的是传入的回调函数。本质上就是useMemo的语法糖。
注意:不要滥用useMemo、useCallBack
使用useMemo、useCallBack时,本身会产生额外的开销,并且这两个方法必须和memo搭配使用,否则很可能会变成负优化。
因此,在实际项目中,需要结合实际场景,评估重复渲染和创建useCallBack/useCallBack的开销来判断到底用不用useCallBack、useMemo。
总结
老版本:子组件中在shouldComponentUpdate判断是否更新
新版本: 使用memo
* 父组件 => 子组件:
1. Props
2. ref
* 子组件 => 父组件:
3. 回调函数
4. 通过事件冒泡机制
* 兄弟组件之间:
5. 利用父组件通信
* 不相关的组件之间:
6. Context
7. Portals:适用的场景 Tooltip、Modal、Popup、Dropdown等
8. 全局变量
9. 观察者模式:可以通过给document添加自定义事件实现
10. redux/mobx/zustand/jotai/recoil/valtio等
详细介绍:10种React组件之间通信的方法_react组件通信的方法_jialiang808的博客-CSDN博客
context/redux/mobx/zustand/jotai/recoil/valtio
【前端状态管理】React 状态管理工具如何选 context/redux/mobx/zustand/jotai/recoil/valtio_AwesomeDevin的博客-CSDN博客
高阶函数:如果一个函数 接受一个或多个函数作为参数或者返回一个函数 就可称之为 高阶函数 。
高阶组件:如果一个函数 接受一个或多个组件作为参数并且返回一个组件 就可称之为 高阶组件。
React 中的高阶组件主要有两种形式:属性代理 和 反向继承。
属性代理类型的高阶组件中可以做什么呢?
- function MyComponent() {
- for (let i = 0; i < 5; i++) {
- const [count, setCount] = useState(0);
-
- useEffect(() => {
- console.log(`Count is: ${count}`);
- }, []);
- }
-
- return <div>My Component</div>;
- }
在上述代码中,循环中的每次迭代都会创建一个新的状态 count 和对应的 setState 函数 setCount,以及一个 useEffect。由于每次循环都会创建新的状态和副作用,而 useEffect 中依赖项为空数组,只会执行一次,因此 console.log 只会输出 "Count is: 0",而不会根据不同的循环迭代更新 count 的值。
https://blog.csdn.net/weixin_46116626/article/details/12469393911
React 性能优化 - 父组件更新时,子组件不进行不必要的更新_jialiang808的博客-CSDN博客
https://blog.csdn.net/jialiang808/article/details/131776326
在 React 中,useRef
是一个 Hook,用于在函数组件中创建和访问持久化的引用。useRef
提供了一种方式来在函数组件中存储和访问不会触发重新渲染的数据。与 useState
不同,useRef
创建的引用对象的值可以在多次渲染之间保持不变,并且在更新其值时不会引起组件重新渲染。
useRef
的主要用途有以下几个方面:
访问 DOM 元素:通过 useRef
创建一个引用对象,并将其赋值给 JSX 元素的 ref
属性,从而可以在函数组件中访问到对应的 DOM 节点。
缓存变量:由于函数组件在每次渲染时都会重新执行,可以使用 useRef
来缓存变量,确保变量在多次渲染之间保持不变,类似于类组件中的实例变量。
存储其他值:useRef
可以用于存储其他不需要触发组件重新渲染的值。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。