本文以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
、 componentWillReceiveProps
getSnapshotBeforeUpdate
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
决定是否setData
props
变更需要在父组件同级使用 useMemo
包裹子组件componentWillUpdate
useEffect
的第二个参数是更新依赖,相当于componentDidUpdate
useEffect
的返回函数 对应 componentWillUnmount
组件的生命周期钩子与页面相比
onLoad
、onReady
、onShow
、onHide
componentWillReceiveProps
钩子
props
改变,会依次触发componentWillReceiveProps
、shouldComponentUpdate
、componentWillUpdate
、render
、componentDidUpdate
componentDidHide
static getDerivedStateFromProps
会替代三个will
,比页面级组件多了一个componentWillReceiveProps
react
有两个处理错误的生命周期 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
以及子组件的卸载componentWillUnmount
Taro.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 许可协议。转载请注明出处!