九、【React基础】组件的生命周期

访问官网 ReactDOM 了解更多DOM 的特定方法

1、旧生命周期

在这里插入图片描述

当前版本虽然依然全部可用,但是自16.x版本就开始说要删除其中的 componentWillMountcomponentWillReceivePropscomponentWillUpdate;而且这三个钩子也基本万年不用一次,建议不要使用

1.1、单组件生命周期

1.1.1、生命周期

1.1.1.1、初始化阶段:由 ReactDOM.render() 触发—初次渲染
  1. constructor()

  2. componentWillMount():组件挂载前置;组件将被挂载

  3. render() 必用

  4. componentDidMount():组件挂载完毕 常用

    1. 可以接收2个参数 (prevProps, prevState),既挂载前收到的props和初始化时创建的state
    2. 一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
1.1.1.2、更新阶段:由组件内部 this.setSate() 或父组件重新render触发
  1. shouldComponentUpdate():组件更新阀门,判断是否进行更新

    1. 可以接收2个参数 (nextProps, nextState)
    2. 可直接调forceUpdate()绕过阀门进行强制更新
  2. componentWillUpdate():组件更新前置;组件将要更新

    1. 可以接收3个参数(prevProps, prevState, snapshot)
  3. render() 必用

  4. componentDidUpdate():组件更新完毕

1.1.1.3、卸载组件:由 ReactDOM.unmountComponentAtNode() 触发
  1. componentWillUnmount():组件卸载前置;组件将要被卸载,这里可以交代后事 常用
    1. 一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

1.1.2、CODE

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>2_react生命周期(旧)</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		//创建组件
		class Count extends React.Component {

			//构造器
			constructor(props) {
				console.log('Count---constructor');
				super(props)
				//初始化状态
				this.state = { count: 0 }
			}

			//组件将要挂载的钩子
			componentWillMount() {
				console.log('Count--组件挂载前置--componentWillMount');
			}

			//组件挂载完毕的钩子
			componentDidMount() {
				console.log('Count--组件挂载完毕--componentDidMount');
			}

			//控制组件更新的“阀门”
			shouldComponentUpdate() {
				console.log('Count--组件更新阀门--shouldComponentUpdate');
				return true // 必须返回boolean且只有返回true才会继续执行更新流程
			}

			//组件将要更新的钩子
			componentWillUpdate() {
				console.log('Count--组件更新前置--componentWillUpdate');
			}

			//组件更新完毕的钩子
			componentDidUpdate() {
				console.log('Count--组件更新完毕--componentDidUpdate');
			}

			//组件将要卸载的钩子
			componentWillUnmount() {
				console.log('Count--组件卸载前置--componentWillUnmount');
			}

			//加1按钮的回调
			add = () => {
				//获取原状态
				const { count } = this.state
				//更新状态
				this.setState({ count: count + 1 })
			}

			//卸载组件按钮的回调
			death = () => {
				ReactDOM.unmountComponentAtNode(document.getElementById('test'))
			}

			//强制更新按钮的回调
			force = () => {
				this.forceUpdate() // 绕过更新阀门直接强制更新
			}

			render() {
				console.log('Count--组件渲染钩子--render');
				const { count } = this.state
				return (
					<div>
						<h2>当前求和为:{count}</h2>
						<button onClick={this.add}>点我+1</button>
						<button onClick={this.death}>卸载组件</button>
						<button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
					</div>
				)
			}
		}

		//渲染组件
		ReactDOM.render(<Count />, document.getElementById('test'))
	</script>
</body>
</html>

1.1.3、Result

在这里插入图片描述


1.2、嵌套组件生命周期

1.2.1、组件将要接收 props

  • componentWillReceiveProps(props):组件接收 props 前置
    • 注意点:第一次传的不算(首次渲染不会调此钩子),如果更名为 componentWillReceiveNewProps 更好理解

1.2.2、CODE

//父组件A
class A extends React.Component {
    //初始化状态
    state = { carName: '奔驰' }

    changeCar = () => {
        this.setState({ carName: '奥拓' })
    }

    render() {
        return (
            <div>
                <div>我是A组件</div>
                <button onClick={this.changeCar}>换车</button>
        		<hr />
            	<B carName={this.state.carName} />
			</div>
        )
    }
}

//子组件B
class B extends React.Component {
    //组件将要接收新的props的钩子
    componentWillReceiveProps(props) {
        console.log('B---componentWillReceiveProps', props);
    }

    //控制组件更新的“阀门”
    shouldComponentUpdate() {
        console.log('B---shouldComponentUpdate');
        return true
    }
    //组件将要更新的钩子
    componentWillUpdate() {
        console.log('B---componentWillUpdate');
    }

    //组件更新完毕的钩子
    componentDidUpdate() {
        console.log('B---componentDidUpdate');
    }

    render() {
        console.log('B---render');
        return (
            <div>我是B组件,接收到的车是:{this.props.carName}</div>
    	)
    }
}

//渲染组件
ReactDOM.render(<A/>, document.getElementById('test'))

1.2.3、Result

在这里插入图片描述


2、新生命周期

在这里插入图片描述

2.1、变化

2.1.1、即将废弃的 3 个老钩子

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

如果在新版本想继续使用这三个废弃的钩子,则必须在前面加上 “UNSAFE_” 前缀,这里的 “unsafe” 不是指安全性,而是表示使用这些生命周期的代码在 React 的未来版本中更有可能出现 bug,尤其是在启用异步渲染之后。具体可参考官博 异步渲染之更新(为未来规划计)

2.1.2、新增 2 个钩子(万年不用)

  • getDerivedStateFromProps:从Props获取派生状态。此方法适用于==罕见==的用例,即 state 的值在任何时候都取决于 props。派生状态会导致代码冗余,并使组件难以维护
    • 可以接收2个参数,没错就是 (props, state)
    • 必须声明为 static 静态方法
    • 必须返回一个 state 对象或者 null
  • getSnapshotBeforeUpdate:在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期方法的任何返回值将作为参数传递给 componentDidUpdate()此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等。
    • 可以接收2个参数 (prevProps, prevState)
    • 必须返回 snapshot 的值或 null

2.2、新生命周期

新钩子已经红色标出,由于根本不用,所以未加粗突出,甚至完全可以忽略这俩小透明

2.2.1、初始化阶段:由 ReactDOM.render() 触发—初次渲染

  1. constructor()

  2. static getDerivedStateFromProps()

  3. render() 必用

  4. componentDidMount() 常用

2.2.2、更新阶段:由组件内部 this.setSate() 或父组件重新render触发

  1. static getDerivedStateFromProps()

  2. shouldComponentUpdate()

  3. render() 必用

  4. getSnapshotBeforeUpdate

  5. componentDidUpdate()

2.2.3、卸载组件:由 ReactDOM.unmountComponentAtNode() 触发

  1. componentWillUnmount() 常用

2.3、CODE for getSnapshotBeforeUpdate

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>4_getSnapShotBeforeUpdate的使用场景</title>
	<style>
		.list{
			width: 200px;
			height: 150px;
			background-color: skyblue;
			overflow: auto;
		}
		.news{
			height: 30px;
		}
	</style>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/17.0.1/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/17.0.1/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/17.0.1/babel.min.js"></script>

	<script type="text/babel">
		class NewsList extends React.Component{

			state = {newsArr:[]}

			componentDidMount(){
				setInterval(() => {
					//获取原状态
					const {newsArr} = this.state
					//模拟一条新闻
					const news = '新闻'+ (newsArr.length+1)
					//更新状态
					this.setState({newsArr:[news,...newsArr]})
				}, 1000);
			}

			getSnapshotBeforeUpdate(){
				return this.refs.list.scrollHeight
			}

			componentDidUpdate(preProps,preState,height){
				this.refs.list.scrollTop += this.refs.list.scrollHeight - height
			}

			render(){
				return(
					<div className="list" ref="list">
						{
							this.state.newsArr.map((n,index)=>{
								return <div key={index} className="news">{n}</div>
							})
						}
					</div>
				)
			}
		}
		ReactDOM.render(<NewsList/>,document.getElementById('test'))
	</script>
</body>
</html>

2.4、Result

滑动到哪就可以让内容停在哪,不会随着数据增加而被压到底下

在这里插入图片描述



小白学习参考视频:尚硅谷React教程

中文官网:State & 生命周期

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

纯纯的小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值