本文以taro@3.3.3、react@16.10讲解Taro开发小程序的生命周期,
class页面组件初始化时生命周期
tsximport React from 'react';
import { View } from '@tarojs/components';
class Index extends React.Component {
// 可以使用所有的 React 生命周期方法
constructor(...args: any[]) {
console.log('1. constructor 仅初始化执行一次');
super(args);
}
componentWillMount() {
console.log('2. componentWillMount 仅初始化执行一次', getCurrentInstance().router?.params);
}
componentDidMount() {
console.log('4. componentDidMount 仅初始化执行一次');
}
// 小程序生命周期 onLoad
onLoad(options: unknown) {
console.log('5. onLoad 仅初始化执行一次', '这里能拿到页面参数', options);
}
// 小程序生命周期 onShow
onShow() {
console.log('6. onShow');
}
// 小程序生命周期 onReady
onReady() {
console.log('7. onReady 仅初始化执行一次');
}
render() {
console.log('3. render');
return <View className='index' >
<View>AAAA</View>
</View>;
}
}
export default Index;
补充
关于页面参数,Taro非常灵活,可以在任意生命周期钩子 如 constructor中获取页面参数
tsximport { getCurrentInstance } from '@tarojs/taro';
class Index extends React.Component {
constructor(...args: any[]) {
console.log(getCurrentInstance().router?.params);
super(args);
}
}
export default Index;
tsximport React from 'react';
import { View } from '@tarojs/components';
class Index extends React.Component {
state = {
count : 0,
}
shouldComponentUpdate() {
console.log('1. shouldComponentUpdate', this.state.count === 2);
if (this.state.count === 2) {
return false;
}
return true;
}
componentWillUpdate() {
console.log('2. componentWillUpdate 随页面或子组件更新执行多次');
}
componentDidUpdate(prevProps: Readonly<{}>, prevState: Readonly<{}>, snapshot?: any): void {
console.log('4. componentDidUpdate 随页面或子组件更新执行多次');
}
render() {
console.log('3. render');
return <View className='index' >
<View>{this.state.count}--</View>
</View>;
}
}
export default Index;
注意事项
小程序还有两个生命周期onShow、 onHide 对应taro页面组件中的componentDidShow和componentDidHide
componentDidShow会在小程序切到前台, 返回当前页面执行componentDidHide会在小程序切到后台, 或者跳转到其他页面执行class页面组件卸载时生命周期
tsximport React from 'react';
import { View } from '@tarojs/components';
class Index extends React.Component {
onUnload() {
console.log('onUnload'); // 实测这里不会触发
// 一般情况下建议使用 React 的 componentWillUnmount 生命周期处理页面卸载时的逻辑。
// 当某些特殊情况需要在页面的 onUnload 的同一个事件循环中实现逻辑时才使用它(如对小程序的生命周期执行顺序有强依赖关系时)
}
// 小程序生命周期 onHide
componentDidHide() {
console.log('onHide');
}
componentWillUnmount() {
console.log('componentWillUnmount');
}
render() {
return <View className='index' >
<View>AAAA</View>
</View>;
}
}
export default Index;
页面卸载有两种场景
以上两种场景小程序的处理逻辑一致,实测表现如下
注意一个特殊场景: 当页面重定向到自身页面,会先触发这个页面的卸载,然后重新执行这个页面的初始化生命周期
我们知道react16.4新增了两个生命周期static getDerivedStateFromProps 和 getSnapshotBeforeUpdate
static getDerivedStateFromProps
componentWillMount、 componentWillUpdate、 componentWillReceivePropsgetSnapshotBeforeUpdate
render之后,在componentDidUpdate之前。tsximport React from 'react';
import { View } from '@tarojs/components';
class Index extends React.Component {
// 对应 onPullDownRefresh,
// 除了 componentDidShow/componentDidHide 之外,
// 所有页面生命周期函数名都与小程序相对应
onPullDownRefresh() {
console.log('onPullDownRefresh');
}
render() {
return <View className='index' >
<View>AAAA</View>
</View>;
}
}
export default Index;
函数组件,页面生命周期
tsximport React, { useEffect, useState } from 'react';
import { View } from '@tarojs/components';
import { useReady, useDidShow, useDidHide, usePullDownRefresh } from '@tarojs/taro';
function Index() {
// 可以使用所有的 React Hooks
const [count, setCount] = useState(0);
useEffect(() => {
// 相当于componentDidMount
console.log('useEffect 1');
const timer = setInterval(() => {
setCount((_count) => {
const newCount = _count + 1;
if (newCount === 2) {
clearInterval(timer);
}
return newCount;
});
}, 1000);
return () => {
// 相当于 componentWillUnmount
console.log('clear 1');
};
}, []);
useEffect(() => {
// 相当于componentDidMount + componentDidUpdate(有依赖项的情况)
console.log('useEffect 2');
}, [count]);
/* 对应 onLoad Taro v3.5.0+ 开始支持
useLoad(() => {
console.log('onLoad');
}); */
// 对应 onReady
useReady(() => {
console.log('useReady');
});
// 对应 onShow
useDidShow(() => {
console.log('useDidShow');
});
// 对应 onHide
useDidHide(() => {
console.log('useDidHide');
});
// Taro 对所有小程序页面生命周期都实现了对应的自定义 React Hooks 进行支持
// 详情可查阅:【Hooks】
usePullDownRefresh(() => {});
return <View className='index' >
<View>XX</View>
<View>{count}</View>
</View>;
}
export default Index;
这里我们对标一下页面组件
constructor和componentWillMount 钩子没有了useLoad 目前项目不支持,需要升级 taro 至3.5+shoudleComponentUpdate,
state 进行diff 决定是否setDataprops变更需要在父组件同级使用 useMemo包裹子组件componentWillUpdateuseEffect的第二个参数是更新依赖,相当于componentDidUpdateuseEffect的返回函数 对应 componentWillUnmount组件的生命周期钩子与页面相比
onLoad、onReady、onShow、onHidecomponentWillReceiveProps钩子
props改变,会依次触发componentWillReceiveProps、shouldComponentUpdate、componentWillUpdate、render、componentDidUpdate

componentDidHidestatic getDerivedStateFromProps会替代三个will,比页面级组件多了一个componentWillReceivePropsreact有两个处理错误的生命周期 static getDerivedStateFromError和componentDidCatch 它们的作用是
static getDerivedStateFromError 它将抛出错误错误并返回一个值以更新state, 通常是UI降级使用componentDidCatch 处理副作用 如错误上报以下面的代码,在taro3.3中实测
tsximport React from 'react';
import { View } from '@tarojs/components';
import ClassComp from './ClassComp';
class Index extends React.Component {
state = {
isError : false,
}
static getDerivedStateFromError() {
// 此生命周期在后代组件抛出错误后被调用。它将抛出错误错误并返回一个值以更新state;
console.log('static getDerivedStateFromError--');
return {
isError : true,
};
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {
// 主要用于副作用提交 如错误上报
console.log('componentDidCatch--');
}
render() {
return <View className='index' >
<View>AAAA</View>
{/* 子组件我做了特殊处理 渲染三秒后就报错 */}
{this.state.isError ? '遇到了错误' : <ClassComp count={this.state.count}></ClassComp>}
</View>;
}
}
export default Index;
实测结果如下
static getDerivedStateFromError能捕捉子组件中同步渲染的错误。Taro.onError捕获到。componentWillUnmount以及子组件的卸载componentWillUnmountTaro.onError也会捕获到.onUnhandledRejection可以捕获页面及子组件的Promise报错总结
ErrorBound组件包裹子组件,时期能恢复过来ErrorBound.tsx
tsximport React from 'react';
import { View } from '@tarojs/components';
class Index extends React.Component<{children: React.ReactNode}>{
state = {
isError : false,
}
componentWillUnmount(): void {
console.log('ErrorBound componentWillUnmount');
}
static getDerivedStateFromError() {
return {
isError : true,
};
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {
// 主要用于副作用提交 如错误上报
console.log('ErrorBound componentDidCatch--');
}
restore = () =>{
this.setState({isError: false})
}
render() {
return <View className='index' >
<View>ErrorBound</View>
{this.state.isError ? <View onClick={this.restore}>遇到了错误,点击重试</View> : this.props.children}
</View>;
}
}
export default Index;
tsximport React, { Component } from 'react'
class App extends Component {
// 可以使用所有的 React 生命周期方法
componentDidMount() {
console.log('1. APP componentDidMount');
}
// 对应 onLaunch
onLaunch(launchParams) {
console.log('2. APP onLaunch');
}
// 对应 onShow
componentDidShow() {
console.log('3. APP componentDidShow');
}
// 对应 onHide
componentDidHide() {
console.log('APP componentDidHide');
}
// Taro v3.5.0+ 开始支持
// onError (error) {}
// Taro v3.5.10+ 开始支持
// onUnhandledRejection (Object){}
render() {
// 在入口组件不会渲染任何内容,但我们可以在这里做类似于状态管理的事情
return this.props.children
}
}
export default App
我测试了下有以下结论
componentDidMount、onLaunch、componentDidShow, APP的生命周期早于页面的生命周期app.tsx里面不要写任何模版内容 除了context, 因此对应React页面更新的钩子,都不能用onPageNotFound 启动时页面不存在(测试微信会触发,支付宝不知道怎么测)本文作者:郭郭同学
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!