持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第16天,点击查看活动详情
组件的生命周期
事先准备
我们在页面中添加一个按钮,每次点击时变量自增1,在页面中将该数值显示出来,效果图如下:
案例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>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>
<!-- 设置类型为babel -->
<script type="text/babel">
class Count extends React.Component {
// 初始化状态
state = { count: 0 }
// 按钮回调
addOne = () => {
// 获取原状态
const { count } = this.state
// 更新状态
this.setState({ count: count + 1 })
}
render() {
const { count } = this.state
return (
<div>
<h2>当前求和为:{count}</h2>
<button onClick={this.addOne}>增加 1</button>
</div>
)
}
}
ReactDOM.render(<Count />, document.getElementById("test"))
</script>
</body>
</html>
生命周期的引入
上面的图是React生命周期的执行顺序图,实际上是不是这样呢?我们将涉及到的勾子函数都实现一下,在控制台打印出来看一下是不是这样
组件挂载顺序:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>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>
<!-- 设置类型为babel -->
<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')
}
// 挂载组件
render() {
console.log('Count: render')
const { count } = this.state
return (
<div>
<h2>当前求和为:{count}</h2>
<button onClick={this.addOne}>增加 1</button>
</div>
)
}
// 按钮回调
addOne = () => {
// 获取原状态
const { count } = this.state
// 更新状态
this.setState({ count: count + 1 })
}
}
ReactDOM.render(<Count />, document.getElementById("test"))
</script>
</body>
</html>
下图中可以看到,组件确实是按照这个顺序进行挂载的:
shouldComponentUpdate
该函数用来控制组件的状态更新,当其返回true时允许状态更新,返回false时则拒绝状态更新,不自定义该函数当话默认返回true。
自定义不返回时的效果:
shouldComponentUpdate(){
console.log('Count: shouldComponentUpdate')
}
返回false时的效果:
shouldComponentUpdate(){
console.log('Count: shouldComponentUpdate')
return false
}
返回true时的效果:
shouldComponentUpdate(){
console.log('Count: shouldComponentUpdate')
return true
}
在上图的效果我们可以看到,当更新的阀门返回true时,组件还触发来更新前与更新后的勾子函数,上面的这个流程顺序为:
setState() -> shouldComponentUpdate() -> componentWillUpdate() -> render() -> componentDidUpdate()
是常规的更新顺序,图中还有一个强制更新函数,它不需要通过状况控制的阀门即可实现组件更新:
// 新增一个强制更新按钮
<button onClick={this.force}>强制更新</button>
// 添加按钮回调
force = () => {
this.forceUpdate()
}
图中可以看到,shouldComponentUpdate函数并没有被执行:
上面说了setState和forceupdate这两条线路,我们再说一下父组件componentWillReceiveProps的这条线路吧
需要注意的是,该函数在组件第一次渲染时并不会触发,只有当祖父件状态更新,从新render时,子组件才会触发该函数
class Facher extends React.Component {
state = { name: '张三' }
changeName = () => {
this.setState({ name: '张三三' })
}
render() {
return (
<div>
<h2>我是父组件</h2>
<button onClick={this.changeName}>改名</button>
<Children name={this.state.name} />
</div>
)
}
}
class Children extends React.Component {
componentWillReceiveProps(){
console.log('Children: componentWillReceiveProps')
}
render() {
return (
<div>
<h2>我是子组件,名字是:{this.props.name}</h2>
</div>
)
}
}
ReactDOM.render(<Facher />, document.getElementById("test"))
初始化读取父组件props时:
父组件更新状态从新render时: