React 组件在其生命周期中有多个阶段,每个阶段都有特定的生命周期函数(Lifecycle Methods)。这些函数允许你在组件的不同阶段执行特定的操作。以下是 React 组件生命周期的主要阶段及其对应的生命周期函数,并结合了 React 16.3+ 的变化。
一、挂载阶段(Mounting)
在组件首次被挂载到 DOM 时会触发的一系列生命周期函数。
-
constructor(props)
:- 初始化组件的状态和绑定事件处理器。
- 注意:尽量避免在此进行复杂的计算或副作用操作。
constructor(props) { super(props); this.state = { count: 0 }; this.handleClick = this.handleClick.bind(this); // 绑定事件处理器 }
-
static getDerivedStateFromProps(nextProps, prevState)
:- 在组件挂载和更新之前调用,用于根据新的 props 更新 state。
- 返回一个对象来更新 state,或者返回
null
表示不需要更新。
static getDerivedStateFromProps(nextProps, prevState) { if (nextProps.value !== prevState.value) { return { value: nextProps.value }; } return null; }
-
render()
:- 必须实现的方法,用于渲染组件的虚拟 DOM。
- 不应该在这里进行副作用操作(如 API 调用、DOM 操作等)。
render() { return <div>{this.state.count}</div>; }
-
componentDidMount()
:- 组件挂载完成后调用,通常用于发起网络请求、订阅事件等副作用操作。
componentDidMount() { fetch('/api/data').then(response => this.setState({ data: response.data })); }
二、更新阶段(Updating)
当组件的 props 或 state 发生变化时,会触发一系列更新阶段的生命周期函数。
-
static getDerivedStateFromProps(nextProps, prevState)
:- 同挂载阶段的
getDerivedStateFromProps
,用于根据新的 props 更新 state。
- 同挂载阶段的
-
shouldComponentUpdate(nextProps, nextState)
:- 判断组件是否需要重新渲染。返回
false
可以阻止不必要的重新渲染,从而优化性能。
shouldComponentUpdate(nextProps, nextState) { return nextState.count !== this.state.count; }
- 判断组件是否需要重新渲染。返回
-
render()
:- 同挂载阶段的
render()
方法,用于渲染组件的虚拟 DOM。
- 同挂载阶段的
-
getSnapshotBeforeUpdate(prevProps, prevState)
:- 在最新的渲染输出提交给 DOM 之前调用,可以捕获一些 DOM 信息(如滚动位置),以便在
componentDidUpdate
中使用。
getSnapshotBeforeUpdate(prevProps, prevState) { if (prevProps.items.length < this.props.items.length) { return this.listRef.scrollHeight; } return null; }
- 在最新的渲染输出提交给 DOM 之前调用,可以捕获一些 DOM 信息(如滚动位置),以便在
-
componentDidUpdate(prevProps, prevState, snapshot)
:- 组件更新完成后调用,可以在此进行副作用操作(如网络请求、DOM 操作等)。
componentDidUpdate(prevProps, prevState, snapshot) { if (snapshot !== null) { this.listRef.scrollTop = this.listRef.scrollHeight - snapshot; } }
三、卸载阶段(Unmounting)
当组件从 DOM 中卸载时会触发的生命周期函数。
-
componentWillUnmount()
:- 组件卸载和销毁之前立刻调用,通常用于清理工作,如取消网络请求、清除定时器、移除事件监听器等。
componentWillUnmount() { clearInterval(this.timerID); this.subscription.remove(); }
四、错误处理阶段(Error Handling)
当组件抛出错误时会触发的生命周期函数。
-
static getDerivedStateFromError(error)
:- 当子组件抛出错误时调用,用于更新 state 以便显示错误 UI。
static getDerivedStateFromError(error) { return { hasError: true }; }
-
componentDidCatch(error, info)
:- 当子组件抛出错误时调用,通常用于记录错误日志或上报错误。
componentDidCatch(error, info) { logErrorToService(error, info); }
五、React 16.3+ 生命周期变化
随着 React 16.3+ 的发布,部分生命周期函数被废弃或新增了一些新的生命周期函数:
-
废弃的生命周期:
componentWillMount
(建议使用componentDidMount
)componentWillReceiveProps
(建议使用static getDerivedStateFromProps
)componentWillUpdate
(建议使用getSnapshotBeforeUpdate
)
-
新增的生命周期:
getDerivedStateFromProps
:用于在挂载和更新前根据 props 更新 state。getSnapshotBeforeUpdate
:在最新的渲染输出提交给 DOM 之前调用,捕获一些 DOM 信息。
钩子函数(Hooks)
随着 React Hooks 的引入,许多类组件的生命周期方法可以通过钩子函数来实现:
-
useEffect
:- 相当于
componentDidMount
、componentDidUpdate
和componentWillUnmount
的组合。
useEffect(() => { // 类似 componentDidMount 和 componentDidUpdate fetchData().then(data => setState({ data })); // 清理函数,类似 componentWillUnmount return () => { cleanup(); }; }, [props.userID]); // 依赖项数组
- 相当于
-
useLayoutEffect
:- 类似
useEffect
,但在所有 DOM 变更之后同步调用,适用于需要同步执行的副作用操作。
- 类似
-
useMemo
和useCallback
:- 用于性能优化,类似于
shouldComponentUpdate
。
- 用于性能优化,类似于
总结
React 组件的生命周期分为三个主要阶段:挂载(Mounting)、更新(Updating)和卸载(Unmounting)。每个阶段都有相应的生命周期函数,帮助开发者在组件的不同生命周期中执行特定的操作。
- 挂载阶段:初始化状态、渲染组件、发起数据请求等。
- 更新阶段:判断是否需要重新渲染、捕获 DOM 信息、执行副作用操作等。
- 卸载阶段:清理资源、取消订阅等。
通过合理使用这些生命周期函数,可以构建出更加健壮和高效的 React 应用程序。同时,现代 React 开发中推荐使用 Hooks 来替代类组件的生命周期方法,以简化代码并提高可维护性。
理解这些生命周期函数及其作用,不仅有助于编写高效且易于维护的 React 组件,还能更好地应对复杂的应用场景。