react组件的生命周期
React组件的生命周期分为三个阶段:组件的创建阶段、组件的运行阶段、组件的销毁阶段
1.组件的创建阶段
//1.生命周期第一个执行的是静态属性(只会执行一次)
// 静态属性:设置props的初始值(在使用当前组件的时候,没有给当前组件传递props的时候,该初始值会生效)
static defaultProps = {
initcount: 1000
}
static propTypes = {
// 使用 prop-types 包 来定义 initcount 为 number 类型
// isRequired 表示这个props属性是必须要传递的
initcount: ReactTypes.number.isRequired
}
//2.生命周期第二个执行的是constructor 构造函数 (执行一次)
// 在创建组件对象的时候会自动调用构造函数
constructor(props) {
console.log("constructor")
super(props)
//在构造函数中指定组件的私有数据
this.state = {
count: props.initcount
}
this.divRef = React.createRef()
}
//3.当子组件接收到新的props会执行,在react16.4版本以后,setState修改state数据之后也会触发这个方法(执行多次)
// 在该方法中不能通过this.setSate来修改state数据,因为在staic修饰的方法中就没有this
//作用:将传递的props映射到state里面
//参数: nextProps 外部传递过来的props属性
// prevState 之前的state状态
static getDerivedStateFromProps(nextProps, prevState) {
console.log("getDerivedStateFromProps", nextProps, prevState)
//获取到父组件中传递过来的initcount值
const { initcount } = nextProps;
//当父组件中传递过来的initcount发生改变了
if (initcount != prevState.prevCount) {
//在方法中返回{count:initcount} 替换掉当前state中的 count值
return {
count: initcount,
prevCount:initcount
}
}
//如果父组件中传递过来的initcount没有变化,就返回一个空对象(此时不对当前的state做任何修改)
return null
}
//4.创建虚拟dom,但是虚拟dom还没有挂载到页面 (执行多次)
// render函数中不能使用setState()来修改state的数据,因为会死循环
render() {
console.log("render", this.divRef.current) //null
return (<div ref={this.divRef}>
哈哈Counter {this.state.count}
</div>)
}
//5.虚拟dom已经挂载到页面,此时可以获取到最新的页面 (执行一次)
componentDidMount() {
console.log("componentDidMount", this.divRef.current, this.state) //null
}
2.组件运行阶段
// 第一个会执行:static getDerivedStateFromProps
// 当父组件给子组件传递的props发生变化的时候,会执行该方法。
// 在react16.4版本以后,当前组件的state发生变化,会触发forceUpdate方法,然后还是会触发该方法
// 第二个会执行: shouldComponentUpdate
// 在这个函数中,我们可以设置指定条件下去更新页面,指定条件下不更新页面。这个函数中入参props和state都是最新的
// 在该方法中不能通过this.setSate来修改state数据
shouldComponentUpdate(nextProps, nextState) {
console.log("shouldComponentUpdate", nextProps, nextState)
// 在 shouldComponentUpdate 中要求必须返回一个布尔值
// 在 shouldComponentUpdate 中,如果返回的值是 false,则不会继续执行后续的生命周期函数,而是直接退回到了运行中的状态,此时后续的render函数并没有被调用,因此页面不会被更新,但是组件的 state 状态,却被修改了;
// return nextState.count % 2 == 0 ? true : false;
return true;
}
//第三个会执行:render 此时会重新构建虚拟dom,但是新的虚拟dom还没有渲染到页面
//第四个会执行getSnapshotBeforeUpdate 函数
// 在该方法中不能通过this.setSate来修改state数据
getSnapshotBeforeUpdate() {
console.log("getSnapshotBeforeUpdate")
return {}
}
//第五个执行componentDidUpdate 函数
// 在该方法中不能通过this.setSate来修改state数据
//表示组件已经更新完毕 此时可以获取到最新的页面
componentDidUpdate() {
console.log("componentDidUpdate", this.state)
}
3.组件的销毁阶段
1 | componentWillUnmount() { |
//很关键的,我们获取当前rootNode的scrollHeight,传到componentDidUpdate 的参数perScrollHeight
//在render方法调用之后,在componentDidUpdate之前执行,我们可以在这个方法中获取到元素的滚动位置的信息
//还可以在该方法中做一些样式的微调
getSnapshotBeforeUpdate() {
//console.log(this.rootNode.clientHeight)
//this.rootNode.style.backgroundColor = "red";
return this.rootNode.scrollHeight;
}