REACT-生命周期
一、初始化阶段
官方将componentWillMount废除。在 componentWillMount进行异步请求,能使数据返回的更快。但,componentWillMount 结束后,render 会立刻被触发,但此时componentWillMount中的异步请求结果可能还未返回结果,一单结果返回会重新render,所以说即使在componentWillMount就进行了异步请求,在返回数据后又会重新render,这会导致服务端渲染场景下的冗余请求等额外问题,得不偿失。因此与在componentDidMount来请求没他大差别,所以官方将它废除。
export default class App extends Component {
constructor(){
super()
this.state = {
value:'aaa'
}
}
//v16.2已被标记弃用,不推荐使用,主要的原因是因为新的异步架构会导致它被多次调用,所以网络请求以及事件绑定应该放到 componentDidMount 中
UNSAFE_componentWillMount(){
console.log('componentWillMount',this.state.value,document.getElementById('li'))
//第一次上树前的,最后一次修改状态的机会
this.setState({value:'bbb'})//会调用render函数
//初始化数据
}
componentDidMount(){
console.log('componentDidMount',this.state.value,document.getElementById('li'))
//数据请求axios
//订阅函数调用
//setInterval
//基于创建好的dom进行一切初始化
}
render() {
//只能访问this.props和this.state,不允许修改状态和操作dom
console.log('render')
return (
<div>
<li id='li'>lili</li>
</div>
)
}
}
二、运行中阶段
React v16 弃用 componentWillReceiveProps(nextProps)
- 最先获得父组件传来的props,可以进行ajax或逻辑处理,也可以将获取的属性转化成孩子的状态
- 这种方式十分适合父子组件的互动,通常是父组件需要通过某些状态控制子组件渲染亦或销毁
//nextProps: 表示下一个props。
UNSAFE_componentWillReceiveProps(nextProps) {
if (this.props.sharecard_show !== nextProps.sharecard_show){
//在这里我们仍可以通过this.props来获取旧的外部状态
//通过新旧状态的对比,来决定是否进行其他方法
if (nextProps.show){
}
}
}
shouldComponentUpdate(nextProps, nextState)
//this.props: 表示上一个props。this.state: 表示上一个state的值。
//nextProps: 表示下一个props。nextState: 表示下一个state的值。
shouldComponentUpdate(nextProps, nextState) {
//函数默认返回true,返回false会阻止render调用更新
return this.state.data!== nextState.data
}
React v16 弃用 componentWillUpdate(nextProps, nextState)
//this.props: 表示上一个props。this.state: 表示上一个state的值。
//nextProps: 表示下一个props。nextState: 表示下一个state的值。
UNSAFE_componentWillUpdate(nextProps, nextState) {
}
componentDidUpdate(prevProps, prevState, snapshot)
提示:为避免无限循环或重复调用,所有网络请求和操作dom都必须位于条件语句中
//prevProps: 表示上一个props。prevState: 表示上一个state的值。
//this.props: 表示下一个props。this.state: 表示下一个state的值。
//snapshot:getSnapshotBeforeUpdate()方法返回的值
componentDidUpdate(prevProps, prevState, snapshot) {
if (prevState.data !== this.state.data) {
// Now fetch the new data here.
}
}
三、销毁阶段
componentWillUnmount
react在组件卸载的时候也是遵循render的执行顺序,从最顶层组件逐级向下执行componentWillUnmount生命周期。
componentDidMount() {
window.onresize = () => {
console.log('resize')
}
//this为当前组件实例,挂载到当前实例上
this.timer = setInterval(() =>{
console.log('111111')
},1000)
}
componentWillUnmount() {
window.onresize = null
clearInterval(this.timer)
}
四、老生命周期中的问题
React16 废弃的生命周期有 3 个 will:
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate
废弃的原因,是在 React16 的 Fiber 架构中,可以中间进行暂停重启操作,调和过程会多次执行 will 周期,不再是一次执行,失去了原有的意义。此外,多次执行,在周期中如果有 setState 或 dom 操作,会触发多次重绘,影响性能,也会导致数据错乱. 因而会有 UNSAFE 开头。
五、 新生命周期
getDerivedStateFromProps
- getDerivedStateFromProps(从属性获取派生状态): 第一次的初始化组件以及后续的更新过程中(包括自身状态更新以及父传子) ,return返回一个对象与页面当前状态对象组合作为新的state(相同字段的进行修改),返回null则说明不需要在这里更新state
- 这里为什么使用静态方法(static)呢?使某些生命周期保持静态,以防止不安全地访问实例属性,乱改状态
class Table extends React.Component {
state = {
list: []
}
static getDerivedStateFromProps (props, state) {
//访问不到this
//不能使用setState
//将props转为状态
return {
list: props.list
}
}
render () {
.... // 展示 list
}
}
Class ColorPicker extends React.Component {
state = {
color: '#000000',
prevPropColor: ''
}
static getDerivedStateFromProps (props, state) {
if (props.color !== state.prevPropColor) {
return {
color: props.color
prevPropColor: props.color
}
}
return null
}
... // 选择颜色方法
render () {
.... // 显示颜色和选择颜色操作
}
}
因为getDerivedStateFromProps被定义为静态方法,所以不能够间接应用this.×××,因而咱们须要对类进行实例化,才应用类中定义的办法
class InstrumentCommand extends PureComponent {
......
static getDerivedStateFromProps(nextProps, preState) {
const {match: {params: {instrumentId}}} = nextProps;
if (instrumentId !== preState.instrumentId) {
new InstrumentCommand(nextProps).implementDispatch(instrumentId)
}
}
}
getSnapshotBeforeUpdate
- 取代了 componetWillUpdate ,触发时间为update发生的时候,在render之后,dom渲染之前返回一个值,作为componentDidUpdate的第三个参数
下面的例子是模拟来新邮件后默认滚回到更新前的内容位置,要注意的是这个例子只有在内容未滚动的时候有效,因为新增数据后浏览器会自动帮忙滚回到原先的位置
import React, { Component,createRef} from 'react'
export default class App extends Component {
constructor(){
super()
this.state = {
list:[10,9,8,7,6,5,4,3,2,1]
}
this.container = createRef();
}
//取代了 componetWillUpdate ,触发时间为update发生的时候,在render之后,dom渲染之前返回一个值,作为componentDidUpdate的第三个参数
getSnapshotBeforeUpdate(){
console.log('getSnapshotBeforeUpdate')
return [this.container.current.scrollHeight,this.container.current.scrollTop]
}
componentDidUpdate(prevProps,prevState,snapshot) {
console.log(snapshot)
this.container.current.scrollTop = this.container.current.scrollHeight - snapshot[0] + snapshot[1]
}
// componentDidUpdate(prevProps,prevState,[scrollHeight,scrollTop]) {
// this.container.current.scrollTop = this.container.current.scrollHeight - scrollHeight + scrollTop
// }
render() {
//只能访问this.props和this.state,不允许修改状态和操作dom
console.log('render')
return (
<div>
<button onClick={()=>this.setState({list:[...[20,19,18,17,16,15,14,13,12,11],...this.state.list]})}>新增邮件</button>
<div style={{fontSize:'20px',fontWeight:'blod'}}>邮箱应用</div>
<ul style={{height:'500px',overflow:'auto'}} ref={this.container}>
{
this.state.list.map(item => {
return <li style={{height:'100px',background:'pink',marginTop:'15px'}} key={item}>{item}</li>
})
}
</ul>
</div>
)
}
}
``