生命周期函数(钩子函数):
描述一个组件或者从程序从创建到销毁的过程,我们可以在过程中间基于钩子函数完成一些自己的操作.(如,首次渲染时做什么,更新操作做什么等等).
[基本流程]
constructor 创建一个组件
componentWillMount 第一次渲染之前
render 第一次渲染
componentDidMount 第一次渲染之后
[更新流程]
componentWillReceiveProps:父组件把传递给子组件的属性发生改变后触发的钩子函数(子组件先走这个钩子获取最新的状态)
shouldComponentUpdate 是否允许组件重新渲染(允许则执行后面函数,不允许直接结束即可)
componentWillUpdate 重新渲染之前
render 第二次及以后重新渲染
componentDidUpdate 重新渲染之后
[卸载]
卸载:原有渲染的内容是不消失,只不过以后不能基于数据改变视图了 componentWillUnmount: 卸载组件之前(一般不用)(把组件中的定时器等置空)
测试代码
class A extends React.Component{
//=>这个是第一次执行的,执行完成后(给属性设置默认值后才向下执行)
static defaultProps = {};
constructor(){
super()
console.log('子组件----01constructor')
this.state = {
n: 1
}
}
componentWillMount(){
console.log('子组件----02componentWillMount-第一次渲染之前',this.refs.HH) //undefined
// =》在WILL_MOUNT中,如果直接的SET-STATE修改数据,会把状态信息改变,然后RENDER和DID_MOUNT;但是如果SET-STATE是放到一个异步操作中完成(例如:定时器或者从服务器数据),也先会执行RENDER和DID,然后在执行这个异步操作修改状态,紧接着走修改的流程(这样和放到DID_MOUNT中也没有啥区别的),所以我们一般把数据请求放到DID处理
// =》真实项目中的数据绑定,一般第一次组件渲染,我们都是绑定的默认数据,第二次才是绑定的从服务器获取数据,(有些需求我们需要是否存在判断显示隐藏等)
setInterval(()=>{
this.setState({
n: this.state.n+1
})
},5000)
}
componentDidMount(){
console.log('子组件----03omponentDidMount-第一次渲染之后',this.refs.HH) // <div>1</div>
/*
* 真实项目中在这个阶段一般做如下处理:
* 1.控制状态信息更改的操作
* 2.从服务器获取数据,然后修改状态,完成数据绑定
。。。
*/
// setInterval(()=>{
// this.setState({
// n: this.state.n+1
// })
// },5000)
}
render(){
console.log("子组件----04 RENDER")
return <div ref='HH'>{ this.state.n }</div>
}
componentWillReceiveProps(nextProps,nextState){
// 组件属性改变
console.log("子组件--父组件属性改变",this.props.n,nextProps,nextState)
}
shouldComponentUpdate(nextProps,nextState){
console.log("子组件---05shouldComponentUpdate是否允许更新,函数返回TRUE就是允许,返回FALSE就是不允许",nextProps,nextState);
/*
在这个钩子函数中,我们获取的STATE不是最新修改的,而是上一次的sSTATE值
* 例如: 第一次加载完成:5000MS后,我们基于SET
-STATE把N修改为2,但是此处获取的还是1呢
* 但是这个方法有两个参数:
* nextProps:最新修改属性信息
* nextState 最新修改的状态信息
*/
if(nextState.n>3){
return false
}else{
return true
}
}
componentWillUpdate(nextProps,nextState){
// 这里获取的状态是更新之前的,(和SHOULD相同也有两个参数存储最新的信息)
console.log("子组件---06-componentWillUpdate:组件更新之前",this.state.n,nextProps,nextState)
}
componentDidUpdate(){
// 这里获取的状态是更新之后的
console.log("子组件---08-componentDidUpdate:组件更新之后",this.state.n)
}
}
class B extends React.Component{
constructor(){
super()
this.state = {
n: 1
}
console.log('父组件----01 constructor')
}
componentWillMount(){
// setTimeout(()=>{
// this.setState({
// n:2
// })
// },3000)
console.log('父组件----02 componentWillMount')
}
componentDidMount(){
setTimeout(()=>{
this.setState({
n:2
})
},3000)
console.log('父组件----03 componentDidMount')
}
shouldComponentUpdate(nextProps,nextState){
console.log("父组件---05-shouldComponentUpdate:是否允许更新,函数返回TRUE就是允许,返回FALSE就是不允许",nextProps,nextState)
return true;
}
componentWillUpdate(nextProps,nextState){
// 这里获取的状态是更新之前的,(和SHOULD相同也有两个参数存储最新的信息)
console.log("父组件---06-componentWillUpdate:组件更新之前",this.state.n,nextProps,nextState)
}
componentDidUpdate(){
// 这里获取的状态是更新之后的
console.log("父组件---08-componentDidUpdate:组件更新之后",this.state.n)
}
render(){
console.log('父组件----04 render')
return <div>
{/* 把父组件的状态作为属性传递给子组件 */}
<A n = { this.state.n } />
</div>
}
}
旧的生命周期流程图
React最新的生命周期
componentWillMount has been renamed, and is not recommended for use. ==> componentWillMount已重命名,建议不要使用
componentWillReceiveProps has been renamed, and is not recommended for use. ==> details.componentWillReceiveProps已重命名,建议不要使用
...
16.3版本的生命周期
16.4版本的生命周期
react16.3以后
新增了getDerivedStateFromProps,getSnapshotBeforeUpdate
删除了 componentWillMount,componentWillUpdate,componentWillReceiveProps
getDerivedStateFromProps(nextProps, prevState)
getDerivedStateFromProps() ==> 从属性获取派生状态(语义化) ==> 将传入的props映射到state中.
getDerivedStateFromProps是一个静态函数,也就是这个函数不能通过this访问到class的属性,也并不推荐直接访问属性。而是应该通过参数提供的nextProps以及prevState来进行判断,根据新传入的props来映射到state。
注意
如果props传入的内容不需要影响到你的state,那么就需要返回一个null,这个返回值是必须的,所以尽量将其写到函数的末尾;没有返回值会报警告
static getDerivedStateFromProps(nextProps, prevState) {
console.log('子组件-----getDerivedStateFromProps',nextProps,prevState);
const { n } = nextProps;
// getDerivedStateFromProps是一个静态函数,也就是这个函数不能通过this访问到class的属性,也并不推荐直接访问属性。而是应该通过参数提供的nextProps以及prevState来进行判断,根据新传入的props来映射到state。
if(n !== prevState.n){
return {
n // 直接映射到state中
};
}
return null;
}
getSnapshotBeforeUpdate(prevProps, prevState)
getSnapshotBeforeUpdate(prevProps, prevState) => 在render之后调用,state已更新.
应用: 获取render之前的dom状态
在最近的更改被提交到DOM元素前,使得组件可以在更改之前获得当前值,此生命周期返回的任意值都会传给componentDidUpdate()。
注意
getSnapshotBeforeUpdate()必须有返回值,没有返回值会报警告
getSnapshotBeforeUpdate(prevProps,prevState){
console.log("子组件---getSnapshotBeforeUpdate",prevProps,prevState);
return 111
}
// componentDidUpdate第三个参数接受getSnapshotBeforeUpdate()钩子函数的返回值
componentDidUpdate(prevProps, prevState,perScrollHeight){
console.log(prevProps,prevState,perScrollHeight)
// 这里获取的状态是更新之后的
console.log("子组件---08-componentDidUpdate:组件更新之后",this.state.n)
}
测试代码
class A extends React.Component{
//=>这个是第一次执行的,执行完成后(给属性设置默认值后才向下执行)
static defaultProps = {};
constructor(){
super()
console.log('子组件----01constructor')
this.state = {
n: 1
}
}
// getDerivedStateFromProps是一个静态函数,也就是这个函数不能通过this访问到class的属性,也并不推荐直接访问属性。而是应该通过参数提供的nextProps以及prevState来进行判断,根据新传入的props来映射到state。
static getDerivedStateFromProps(nextProps, prevState) {
console.log('子组件-----getDerivedStateFromProps',nextProps,prevState);
const { n } = nextProps;
if(n !== prevState.n){
return {
n // 直接映射到state中
};
}
return null; // 如果返回的null,不会把props中的数据映射到state中
}
componentDidMount(){
console.log()
console.log('子组件----03omponentDidMount-第一次渲染之后',this.refs.HH) // <div>1</div>
}
shouldComponentUpdate(nextProps,nextState){
console.log("子组件---05shouldComponentUpdate是否允许更新,函数返回TRUE就是允许,返回FALSE就是不允许",nextProps,nextState);
if(nextState.n>3){
return false
}else{
return true
}
}
// 获取上一次的值,做一次事情,例如官网给的例子,, 滚动条
// getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()。
getSnapshotBeforeUpdate(prevProps,prevState){
console.log("子组件---getSnapshotBeforeUpdate",prevProps,prevState);
return 111
}
// componentWillUpdate(nextProps,nextState){
// // 这里获取的状态是更新之前的,(和SHOULD相同也有两个参数存储最新的信息)
// console.log("子组件---06-componentWillUpdate:组件更新之前",this.state.n,nextProps,nextState)
// }
componentDidUpdate(prevProps, prevState,perScrollHeight){
console.log(prevProps,prevState,perScrollHeight)
// 这里获取的状态是更新之后的
console.log("子组件---08-componentDidUpdate:组件更新之后",this.state.n)
}
render(){
console.log("子组件----04 RENDER")
return <div ref='HH'>{ this.state.n }</div>
}
}
class B extends React.Component{
constructor(){
super()
this.state = {
n: 1
}
console.log('父组件----01 constructor')
}
// componentWillMount(){
// console.log('父组件----02 componentWillMount')
// }
static getDerivedStateFromProps(nextProps, prevState) {
// // 组件每次被rerender的时候,包括在组件构建之后(虚拟dom之后,实际dom挂载之前),每次获取新的props或state之后;;每次接收新的props之后都会返回一个对象作为新的state,返回null则说明不需要更新state
console.log('父组件-----getDerivedStateFromProps')
return null;
}
componentDidMount(){
setTimeout(()=>{
this.setState({
n:2
})
},3000)
console.log('父组件----03 componentDidMount')
}
shouldComponentUpdate(nextProps,nextState){
console.log("父组件---05-shouldComponentUpdate:是否允许更新,函数返回TRUE就是允许,返回FALSE就是不允许",nextProps,nextState)
return true;
}
getSnapshotBeforeUpdate(nextProps,nextState){
console.log("父组件--getSnapshotBeforeUpdate",nextProps,nextState)
return null;
}
// componentWillUpdate(nextProps,nextState){
// // 这里获取的状态是更新之前的,(和SHOULD相同也有两个参数存储最新的信息)
// console.log("父组件---06-componentWillUpdate:组件更新之前",this.state.n,nextProps,nextState)
// }
componentDidUpdate(){
// 这里获取的状态是更新之后的
console.log("父组件---08-componentDidUpdate:组件更新之后",this.state.n)
}
render(){
console.log('父组件----04 render')
return <div>
{/* 把父组件的状态作为属性传递给子组件 */}
<A n = { this.state.n } />
</div>
}
}