学习地址:https://www.bilibili.com/video/BV1wy4y1D7JT
官方文档:
生命周期理解
- 组件从创建到注销经历的一些特定阶段。
- React组件包含一系列钩子函数(生命周期回调函数),在特定的时刻调用。
- 在定义组件时会在特定的生命周期回调函数中做特定的工作。
生命周期流程图(旧)【注意引入库的版本号】
生命周期流程图(新)【注意引入库的版本号】
重要的钩子
- render():初始化渲染或更新渲染时调用
- componentDidMount():组件挂载完毕,开启监听,发送请求
- componentWillUnmount():组件将要卸载的钩子,做一些收尾工作如清除定时器
即将废弃的钩子
此三个钩子函数在新版本中会在控制台显示警告,需添加‘UNSAFF_’前缀方可使用,以后可能会彻底废弃,不建议使用
- componentWillMount():组件将要挂载的钩子
- componentWillReveiceProps():组件将要接收新的props的钩子
- componentWillUpdate():组件将要更新的钩子
生命周期的三个阶段(旧版本)
- 初始化阶段:由ReactDOM.render()触发----初次渲染
- constructor() 构造器
- componentWillMount() 组件将要挂载
- render()
- componentDidMount() 组件挂载完毕
- 更新阶段:由组件内部this.setState()或父组件重新render()触发,this.forceUpdate()强制更新
- componentWillReveiceProps() 组件将要接受新的props的钩子,父组件重新render时触发
- shouldComponentUpdate() 控制组件更新的‘阀门’,返回一个布尔值,true表示可更新,false表示不可更新。强制更新不受此返回值的影响,即使返回false依然更新。
- componentWillUpdate() 组件将要更新
- render()
- componentDidUpdate() 组件更新完毕
- 卸载组件:由ReactDOM.unmountComponentAtNode()触发
- componentWillUnmount() 组件将要卸载
运行测试(旧版本生命周期)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="test"></div>
<div id="test2"></div>
<!-- react核心库 -->
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<!-- react-dom用于支持react操作dom -->
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<!-- 引入babel 用于将jsx转成js -->
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.js"></script>
<script type="text/babel">
class Count extends React.Component {
// 构造器
constructor(props) {
console.log('count--constructor')
super(props);
// 初始化状态
this.state = { count: 0 }
}
// +1按钮的回调
add = () => {
let { count } = this.state;
this.setState({ count: count + 1 })
}
// 卸载按钮的回调
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById('test'));
}
// 强制更新的回调
force = () => {
this.forceUpdate()
}
// 组件将要挂载
componentWillMount() {
console.log('count--componentWillMount')
}
// 组件挂载完毕
componentDidMount() {
console.log('count--componentDidMount')
}
// 组件将要卸载的钩子
componentWillUnmount() {
console.log('count--componentWillUnmount');
}
// 控制组件更新的‘阀门’,返回一个布尔值,true表示可更新,false表示不可更新
shouldComponentUpdate() {
console.log('count--shouldComponentUpdate');
return true;
}
// 组件将要更新的钩子
componentWillUpdate() {
console.log('count--componentWillUpdate');
}
// 组件更新完毕的钩子
componentDidUpdate() {
console.log('count--componentDidUpdate');
}
render() {
console.log('count--render')
return (
<div>
<h2>当前求和为{this.state.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'));
class A extends React.Component {
state={carName:'aaa'}
change=()=>{
this.setState({carName:'bbb'})
}
render() {
return (
<div>
<div>
组件A
</div>
<button onClick={this.change}>改变</button>
<B carName={this.state.carName} />
</div>
)
}
}
class B extends React.Component {
componentWillReceiveProps(props){
console.log('B--componentWillReceiveProps',props)
}
render() {
return (
<div>
组件B,接收到的参数:{this.props.carName}
</div>
)
}
}
ReactDOM.render(<A />,document.getElementById('test2'))
</script>
</body>
</html>
生命周期的三个阶段(新版本)
- 初始化阶段:由ReactDOM.render()触发----初次渲染
- constructor() 构造器
- static getDerivedStateFromProps()
- render()
- componentDidMount() 组件挂载完毕
- 更新阶段:由组件内部this.setState()或父组件重新render()触发,this.forceUpdate()强制更新
- static getDerivedStateFromProps()
- shouldComponentUpdate() 控制组件更新的‘阀门’,返回一个布尔值,true表示可更新,false表示不可更新。强制更新不受此返回值的影响,即使返回false依然更新。
- render()
- getSnapshotBeforUpdate() 使组件在可能发生更改之前获取一些信息(如滚动位置),此生命周期返回的任何值豆浆作为参数传递给componentDidUpdate()。
- componentDidUpdate() 组件更新完毕
- 卸载组件:由ReactDOM.unmountComponentAtNode()触发
- componentWillUnmount() 组件将要卸载
测试代码(新版本)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="test"></div>
<div id="test2"></div>
<!-- react核心库 -->
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<!-- react-dom用于支持react操作dom -->
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<!-- 引入babel 用于将jsx转成js -->
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.js"></script>
<script type="text/babel">
class Count extends React.Component {
// 构造器
constructor(props) {
console.log('count--constructor')
super(props);
// 初始化状态
this.state = { count: 0 }
}
// +1按钮的回调
add = () => {
let { count } = this.state;
this.setState({ count: count + 1 })
}
// 卸载按钮的回调
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById('test'));
}
// 强制更新的回调
force = () => {
this.forceUpdate()
}
// 从props中得到一个派生状态 及当state中的值在任何时候都取决于props的时候,可以使用此钩子
//派生状态会导致代码冗余,并使组件难以维护
static getDerivedStateFromProps(props,state){
console.log('count--getDerivedStateFromProps',props,state);
return props
}
// 组件将要挂载
// UNSAFF_componentWillMount() {
// console.log('count--componentWillMount')
// }
// 组件挂载完毕
componentDidMount() {
console.log('count--componentDidMount')
}
// 组件将要卸载的钩子
componentWillUnmount() {
console.log('count--componentWillUnmount');
}
// 控制组件更新的‘阀门’,返回一个布尔值,true表示可更新,false表示不可更新
shouldComponentUpdate() {
console.log('count--shouldComponentUpdate');
return true;
}
// 组件将要更新的钩子
// UNSAFF_componentWillUpdate() {
// console.log('count--componentWillUpdate');
// }
// 组件更新完毕的钩子
componentDidUpdate() {
console.log('count--componentDidUpdate');
}
render() {
console.log('count--render')
return (
<div>
<h2>当前求和为{this.state.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'));
class A extends React.Component {
state = { carName: 'aaa' }
change = () => {
this.setState({ carName: 'bbb' })
}
render() {
return (
<div>
<div>
组件A
</div>
<button onClick={this.change}>改变</button>
<B carName={this.state.carName} />
</div>
)
}
}
class B extends React.Component {
// UNSAFF_componentWillReceiveProps(props) {
// console.log('B--componentWillReceiveProps', props)
// }
render() {
return (
<div>
组件B,接收到的参数:{this.props.carName}
</div>
)
}
}
ReactDOM.render(<A />, document.getElementById('test2'))
</script>
</body>
</html>
getSnapshotBeforeUpdate钩子测试
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.list{
height: 180px;
background: skyblue;
width: 200px;
overflow: auto;
}
.news{
height: 30px;
}
</style>
</head>
<body>
<div id="test">
</div>
<!-- react核心库 -->
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<!-- react-dom用于支持react操作dom -->
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<!-- 引入babel 用于将jsx转成js -->
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.js"></script>
<script type="text/babel">
class NewsList extends React.Component {
state = { newsList: [] }
componentDidMount(){
setInterval(() => {
let {newsList} = this.state;
let news = `新闻${newsList.length + 1}`;
this.setState({newsList:[news,...newsList]});
}, 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.newsList.map((item, index) => {
return <div key={index} className="news">{item}</div>
})}
</div>
)
}
}
ReactDOM.render(<NewsList />, document.getElementById('test'));
</script>
</body>
</html>