目录
16.3之前的生命周期:
16.3之后的生命周期:
1、React生命周期阶段
2、在React中网络请求在哪个生命周期中发起?
16.3之前的生命周期:
![](https://img-blog.csdnimg.cn/6e546645b9fb4f87b1e06b3bcf67db7c.png)
16.3之后的生命周期:
![](https://img-blog.csdnimg.cn/9e42e2a8654244f39125a37a86027968.png)
1、React生命周期阶段
⽬前 React 16.8+ 的⽣命周期分为三个阶段:挂载阶段、更新阶段、卸载阶段
在 React 16 版本中,三个之前的生命周期被标识为废弃,并在 React 17 中计划全部删除它们:
当它们被删除后,将会只保留三个添加了UNSAVE_
前缀的函数版本,作为向下兼容用途。因此我们在新项目中,要尽量避免使用这几个生命周期而使用最新的生命周期函数。
因此我们在新项目中,要尽量避免使用这几个生命周期而使用最新的生命周期函数。
挂载阶段:
constructor、getDerivedStateFromProps、render、componentDidMount
constructor:组件的构造函数,它会最先被执⾏,我们通常在构造函数⾥初始化 state
状态对象、或给⾃定义⽅法绑定 this
getDerivedStateFromProps:
- 相当于componentwillmount 和 componentWillReceiveProps合并(课看上面的图理解)
- 这是个静态⽅法,当我们接收到新的属性后想要去修改
state
时可以使用,该方法类似于 componentWillReceiveProps,可以用来控制 props 更新 state 的过程。它返回一个对象表示新的 state。如果不需要更新组件,返回 null 即可。
- 主要是应用在于封装组件时调用,组件的state取决于props变化
- 无条件的根据 props来更新内部 state,也就是只要有传入 props值, 就更新 state
- 只有 props 值和 state值不同时才更新 state 值
// 若state的值在任何时候都取决于props,那么可以使用getDerivedStateFromProps
这不就是和React.useEffect(()=>{},[]),中的依赖参数同等效果,我们在封装组件时可以用到
类组件:
class List extends React.Component {
state = {
list: []
}
static getDerivedStateFromProps(props, state) {
if(props.list !== state.list){
return {
list: props.list
}
}
return null;
}
render() {
.... // 展示 list
}
}
函数组件:
// 函数组件
const List = React.memo((props) =>{
const [list,setList] = React.useState([]);
React.useEffect(()=>{
setList(props.list);
}, [props.list]);
return (
.... // 展示 list
)
});
render:这是个只返回需要渲染内容的纯函数,不要包含其它的业务逻辑,可以返回原⽣的 DOM、React 组件、Fragment、Portals、字符串和数字、Boolean 值 和 null 值等内容
componentDidMount:在组件装载后被调⽤,此时可以获取 DOM 节点并操作,对服务器的请求、订阅等操作都可以写在这个地方,但记得要在 componentWillUnmount
中取消订阅,即释放资源
更新阶段:
getDerivedStateFromProps、shouldComponentUpdate、render、getSnapshotBeforeUpdate、 componentDidUpdate
getDerivedStateFromProps:此⽅法在更新、挂载阶段都可能会调⽤
shouldComponentUpdate(nextProps, nextState):该函数有两个参数 nextProps
和 nextState
,表示新的属性和变化之后的状态;它返回⼀个布尔值,true
表示会触发重新渲染,false
则表示不会触发重新渲染,默认返回 true
。我们通常利⽤该⽣命周期来优化 React 程序的性能
render:更新阶段也会触发此⽣命周期
getSnapshotBeforeUpdate(prevProps, prevState):参考下面代码 该⽅法在 render
之后、在 componentDidUpdate
之前被调⽤,它有两个参数prevProps, prevState,表示之前的属性和状态,并且该函数有⼀个返回值,返回值会作为第三个参数传给 componentDidUpdate,
如果不想要返回值则返回 null
即可。该⽣命周期必须与 componentDidUpdate
搭配使⽤
class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// 我们是否在 list 中添加新的 items ?
// 捕获滚动位置以便我们稍后调整滚动位置。
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// 如果我们 snapshot 有值,说明我们刚刚添加了新的 items,
// 调整滚动位置使得这些新 items 不会将旧的 items 推出视图。
//(这里的 snapshot 是 getSnapshotBeforeUpdate 的返回值)
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}
render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
}
componentDidUpdate(prevProps, prevState, snapshot):该⽅法在 getSnapshotBeforeUpdate
⽅法之后被调⽤,它有三个参数表示之前的属性、之前的状态。第三个参数是 getSnapshotBeforeUpdate
所返回的,如果触发某些回调函数时需要⽤到 DOM 元素的状态,则将对⽐或计算的过程迁移⾄ getSnapshotBeforeUpdate
,然后在 componentDidUpdate
中统⼀触发回调或更新状态
卸载阶段:
componentWillUnmount
componentWillUnmount:当组件被卸载或销毁时就会被调⽤,我们可以在这个函数⾥去做一些释放资源的操作,如:清除定时器、取消⽹络请求、清理⽆效的 DOM 元素等
2、在React中网络请求在哪个生命周期中发起?
有人认为 React 中的网络异步请求,应该放在 componentWillMount
这个生命周期函数中发起,这样可以提前进⾏异步请求,以避免⽩屏现象。其实这个观点是有问题的。
由于 JavaScript 中异步事件的性质,当进行异步 API 调⽤时,浏览器会在此期间继续执⾏其他⼯作。因此,当 React 渲染⼀个组件时,它并不会等待 componentWillMount
执行完成任何事情,而是继续往前执行并继续做 render
,没有办法 “暂停” 渲染以等待远程数据的返回
⽽且,在 componentWillMount
中发起请求会存在⼀系列潜在问题:
⽬前官⽅推荐的是在 componentDidmount
中进行异步请求。
如遇到特殊需求,需要提前进行数据的请求,可考虑采用在 constructor
中进行。
另外,由于在 React 17 之后 componentWillMount
被废弃仅保留 UNSAFE_componentWillMount
,所以要慎用该生命周期。