1.生命周期函数
1.1 16版本及以前的
初始化constructor
-->将要渲染componentWillMount
--->已经渲染componentDidMount
--->组件接受传递数据componentWillReceiveProps
----> 是否要更新(shouldComponentUpdate)
---->将要更新componentWillUpdate
---->更新过程render
---->已经更新componentDidUpdate
--->卸载componentWillUnmount
// 组件数据来源 组件本身的状态state(可读可写) 和传递过来props(只读)
/*
react16生命周期函数:分为三个过程 对应的9个钩子函数
1 挂载过程
constructor(初始化类似于beforeCreate),
componentWillMount(渲染前,类似于vue的beforeMount)、
componentDidMount(渲染后,类似于mounted)
2 更新过程
componentWillReceiveProps(将要接受传递数据) 、
shouldComponentUpdate(组件是否要更新)、
componentWillUpdate(组件将要更新)、
render(更新过程)、
componentDidUpdate(组件更新之后)
3 卸载过程 componentWillUnmount() 卸载过程
*/
class S1 extends React.Component{
constructor(props){
// 1 组件构造函数 创建组件对象,构造器里面的this就是指向正在创建的组件对象,state在此处进行初始化,不能访问this.props,这个函数执行完之后this.props才会有值,
console.log("1 组件初始化数据的触发,此处不能访问this.Props")
super()
this.state={
age:10,
b:""
}
}
//WARNING! To be deprecated in React v17. Use componentDidMount instead.
componentWillMount() {
// 不能在此钩子获取DOM节点
console.log("2 组件将要渲染的时候触发,此处不能获取DOM节点",document.getElementById("d1"))
}
componentDidMount() {
// 在此处可以获取DOM节点
console.log("3 组件已经渲染完毕的时候触发",document.getElementById("d1"))
}
//WARNING! To be deprecated in React v17. Use new lifecycle static getDerivedStateFromProps instead.
// 组件将要接受传递数据更新时候触发,需要在此钩子函数里面根据传递的数据是否更新组件(对比更新前后的数据,如果一样了,这时候不需要更新,如果不一样了,需要更新)
// 如果点击修改sex 如果修改了sex改成了女 是更新,再点击由女变成女 不需要更新
// nextProps 更新之后的数据
// this.props 更新之前的数据
componentWillReceiveProps(nextProps) {
console.log("4 组件将要接受传递数据触发",nextProps,this.props)
if(nextProps.bool!=this.props.bool){
// 需要更新 把更新之后数据赋值给本组件的状态b
this.setState({
b:nextProps.bool
},()=>{
// b数据更新成功了 setState是一个异步修改
// 发请求,根据在使用组件的时候传递数据不一样,根据数据发请求或者进行渲染
})
}
}
shouldComponentUpdate(nextProps, nextState) {
console.log("5 组件是否要更新")
//
console.log(this.props.bool,nextProps.bool);
console.log(this.state.b,nextState.b);
// 对比组件接收到的状态是否一致,一致不需要更新
if (this.state.b != nextState.b) return true
else return false
}
//WARNING! To be deprecated in React v17. Use componentDidUpdate instead.
componentWillUpdate(nextProps, nextState) {
console.log("6 组件将要更新")
}
componentDidUpdate(prevProps, prevState) {
console.log("7 组件已经更新")
}
componentWillUnmount() {
console.log("8 组件将要卸载")
}
render() {
console.log("render 更新过程")
return(
<div id="d1">
{this.state.age} --{this.state.b}
{
/*
<button onClick={()=>{
this.setState({age:100})
}}>更新age</button>
*/
}
</div>
)
}
}
class Father extends React.Component{
constructor(props){
super()
this.state = {
sex:"男"
}
}
render(){
return(
<div>
<button onClick={()=>{
this.setState({
sex:'女'
})
}}>更改sex---{this.state.sex}</button>
<S1 bool={this.state.sex}></S1>
</div>
)
}
}
// 16的渲染函数是 参数1渲染的组件 参数2渲染的节点
ReactDOM.render(
<Father></Father>,
document.getElementById("app")
)
1.2 17及以后的生命周期函数
新的钩子函数8个
1 挂载过程
constructor(初始化状态)
---componentWillMount(**删除)
componentDidMount(渲染完毕)
2 更新过程
getDerivedStateFromProps(从props更新状态,要有返回对象;返回对象是组件状态的更新 ,与this.setState一样中的对象一样,不要更改的话返回null)(**componentReceivedProps改名)、
shouldComponentUpdate(是否要更新,需要有返回值是一个布尔值) 、
getSnapshotBeforeUpdate(组件更新前,要有返回对象,返回值是对象)(**componentWillUpdate改名)
render(更新)、
componentDidUpdate(已经更新)
3 卸载过程
/*
新的钩子函数8个
1 挂载过程
constructor(初始化状态)
componentWillMount(删除)
componentDidMount(渲染完毕)
2 更新过程
getDerivedStateFromProps(从props更新状态,要有返回值)(componentReceivedProps改名)、
shouldComponentUpdate(是否要更新) 、
getSnapshotBeforeUpdate(组件更新前,要有返回值)(componentWillUpdate改名)
render(更新)、
componentDidUpdate(已经更新)
3 卸载过程
componentWillUnmount 卸载前
*/
class S1 extends React.Component{
constructor(props){
console.log("1 组件初始化数据的触发")
super()
this.state={
i1:""
}
}
// react17 以及更高的版本把componentWillMount(将要渲染的钩子函数)写的业务路径放在componentDidMount(以及渲染的钩子函数中)
// componentWillMount() {}
componentDidMount() {
console.log("2 组件渲染完毕的钩子函数")
}
// 更新过程
// componentWillReceiveProps(nextProps) {}
// componentWillReceiveProps 被取代了 替换成了getDerivedStateFromProps(从props获取状态)
// derived 获取;
static getDerivedStateFromProps(props, state) {
console.log("3 组件从props中获取数据时候调用,可以调用的多次,初始化的时候也会调用一次",props,state)
if(props.id!=state.i1){
// 当传递数据和当前状态不一样时候,需要把传递数据更新到组件状态上
// -----------------------------------------------------------
// 注意:::返回对象是组件状态的更新 ,把状态的i1更新成props.id
return {
i1:props.id
}
}
return null // 如果传递数据和当前状态一样 不用更新状态
}
shouldComponentUpdate(nextProps, nextState) {
// nextState 更新之后的状态
// this.state.i1
console.log("4 组件是否要更新",nextProps,nextState,this.state)
// 下面四种方式都可以提升渲染效率
// if(nextProps.id != this.state.i1){
if(nextState.i1 != this.props.id){
// if(nextState.i1 != this.state.i1){
// if(nextProps.id != this.props.id){
return true // true 组件要更新; false 组件不更新
}
return false
}
//WARNING! To be deprecated in React v17. Use componentDidUpdate instead.
// componentWillUpdate(nextProps, nextState) {}
// 将要更新的函数componentWillUpdate 被替代了,换成了getSnapshotBeforeUpdate()
// snapshot 快照
getSnapshotBeforeUpdate (prevProps, prevState){
console.log("5 组件在最终更新前触发")
return null
}
componentDidUpdate(prevProps, prevState) {
console.log("6 组件更新之后触发")
}
componentWillUnmount() {
console.log("7 组件更将要卸载的时候触发")
}
render() {
return(
<div id="d1">
{this.state.i1}
</div>
)
}
}
class Father extends React.Component{
constructor(props){
super()
this.state = {
id:1
}
}
render(){
return(
<div>
<button onClick={()=>{
this.setState({
id:2
})
}}>点击修改id--{this.state.id}</button>
<S1 id={this.state.id}></S1>
</div>
)
}
}
const root = ReactDOM.createRoot(document.getElementById("app")).render(<Father/>)
3 扩展,更改生命周期函数的原因。
componentWillReceiveProps为啥被替换为getDerivedStateFromProps???
因为强制开发者去对比props对象和state对象,而不是直接对比props和this.props,
防止开发者会去操作this.props,组件自身的状态将变得不可预测;
老版本对比this.props和nextProps;新版本使用props传递的数据与state自身定义的状态进行对比;
旧的React中componentWilReceiveProps方法是用来判断前后两个props是否相同,如果不同,则将新的props更新到
相应的state上去。在这个过程中我们实际上是可以访问到当前props的,这样我们可能会对this .props做-些奇奇怪怪的
操作,很可能会破坏state数据的单一数据源, 导致组件状态变得不可预测。
而在getDerivedStateFromProps中禁止了组件去访问this.props,强制让开发者吡较nextProps与prevState 中的值,
以确保当开发者用到getDerivedStateFromProps这个生命周期函数时,就是在根据当前的props来更新组件的state,而
不是去访问this props并做其他一些让组件自身状态变得更加不可预测的事情。
那么 componentWillUpdate为什么被改为getSnopshotBeforeUpdate呢??
老版本使用的两个参数是nextProps与nextState进行对比,而componentDidUpdate中是prevProps与prevState;新版本使用prevProps与prevState,与componentDidUpdate中的prevProps与prevState参数相同;
在React开启异步渲染模式后,在执行函数时读到的DOM元素状态并不总是渲染时相同,这就导致在
componentDidUpdate中使用componentWillUpdate中读取到的DOM元素状态是不安全的,因为这时的值很有可能已经
失效了。
而getSnapshotBeforeUpdate会在最终的render之前被调用,也就是说在getSnapshotBeforeUpdate中读取到的DOM
元素状态是可以保证与componentDidUpdate中-致的。