前言
类比以下代码
let div = document.createElement('div')
这是 create/construct 过程div.textContent = 'hi
这是初始化 statedocument.body.appendChild(div)
这是 div 的 mount 过程div.textContent = 'hi2
这是 div 的 update 过程div.remove()
这是 div 的 unmount 过程
同理
- React 组件也有这些过程,我们称为生命周期
一、constructor
在这里初始化
state
二、shouldComponentUpdate
是否需要更新组件
用途
- 它允许我们手动判断是否要进行组件更新,我们可以根据应用场景灵活地设置返回值,以避免不必要的更新(让我们自己确定是否更新)
- 返回
true
表示不阻止 UI 更新 - 返回
false
表示阻止 UI 更新
示例
class App extends React.Component {
constructor(props) {
super(props)
this.state = { n: 1 }
}
onClick = () => {
// onClick 函数里对 n 进行了 +1 -1 操作
this.setState(state => ({ n: state.n + 1 }))
this.setState(state => ({ n: state.n - 1 }))
}
shouldComponentUpdate(newProps, newState) {
if (newState.n === this.state.n) {
return false // 返回 false,表示阻止 render
} else {
return true // 返回 true,表示不阻止 render
}
}
render() {
console.log('render了') // 不加 shouldComponentUpdate 的时候 log 一下看看?
return (
<div>
n: {this.state.n}
<button onClick={this.onClick}>+1</button>
</div>
)
}
}
使用内置 React.PureComponent
使用
React.PureComponent
代替React.Component
PureComponent
会在 render
之前对新旧 state
进行对比(之对比第一层,浅对比),如果对比结果一样,那就不更新
class App extends React.PureComponent {
constructor(props) {
super(props)
this.state = { n: 1 }
}
onClick = () => {
// onClick 函数里对 n 进行了 +1 -1 操作
this.setState(state => ({ n: state.n + 1 }))
this.setState(state => ({ n: state.n - 1 }))
}
render() {
console.log('render了')
return (
<div>
n: {this.state.n}
<button onClick={this.onClick}>+1</button>
</div>
)
}
}
三、render
创建虚拟 DOM
用途
-
展示视图
return (<div>...</div>)
这是虚拟 DOM -
只能有一个根元素
-
如果有两个根元素,就要用
<React.Fragment>
包起来 -
<React.Fragment>
可以缩写成<></>
示例
class App extends React.PureComponent {
constructor(props) {
super(props)
this.state = { n: 1 }
}
onClick = () => {
this.setState(state => ({ n: state.n + 1 }))
}
render() {
return (
<>
n: {this.state.n}
<button onClick={this.onClick}>+1</button>
</>
)
}
}
可以写 if...else...
&& 也可以,|| 也可以
class App extends React.PureComponent {
constructor(props) {
super(props)
this.state = { n: 1 }
}
onClick = () => {
this.setState(state => ({ n: state.n + 1 }))
}
render() {
return (
<>
{this.state.n % 2 === 0 ? <div>偶数</div> : <div>奇数</div>}
<button onClick={this.onClick}>+1</button>
</>
)
}
}
可以写 map
不可以直接写
for
循环,需要用数组,可以用map
来代替
class App extends React.PureComponent {
constructor(props) {
super(props)
this.state = { array: [1, 2, 3] }
}
render() {
return this.state.array.map(n => <div key={n}>{n}</div>)
}
}
记得要写 key
四、componentDidMount
组件已出现在页面
用途
- 在元素插入页面后执行代码,这些代码一般来说应该依赖 DOM
- 比如:获取 div 的高度,就最好在这里写
- 此处可以发起
加载数据
的 AJAX 请求(官方推荐) - 首次渲染会执行此钩子
五、componentDidUpdate
组件已更新
用途
- 在视图更新后执行代码
- 此处也可以发起 AJAX 请求,一般用于
更新数据
- 首次渲染不会执行此钩子
- 在此处
setState
可能会引起无限循环,除非放在 if 里 - 若
shouldComponentUpdate
返回false
,则不触发此钩子
六、componentWillUnmount
组件将要被卸载
用途
- 组件将要
被移出页面然后被销毁
时执行代码 unmount
过的组件不会再次mount
举例
- 如果在
componentDidMount
里监听了window scroll
,那么就要在componentWillUnmount
里取消监听 - 如果在
componentDidMount
里创建了Timer
,那么就要在componentWillUnmount
里取消Timer
- 如果在
componentDidMount
里创建了AJAX
请求,那么就要在componentWillUnmount
里取消请求 - 否则前端页面的内存会很多
- 原则:谁污染谁整治
能用函数组件就用函数组件,别用 class
完。