导航后不调用 `componentDidMount()` 函数
`componentDidMount()` function is not called after navigation
我正在使用 stackNavigator
在屏幕之间导航。我在第二个 activity 中调用 componentDidMount()
函数中的两个 API。当我第一次加载它时,它加载成功。然后我按后退按钮返回到第一个 activity。然后,如果我再次转到第二个 activity,则不会调用 API,我会收到渲染错误。我找不到任何解决方案。如有任何建议,我们将不胜感激。
在 React 中,componentDidMount 仅在组件处于 mounted.I 时被调用,认为您正在尝试做的是在返回 StackNavigator 时调用 API。当您在父屏幕上像这样调用导航时,您可以将回调函数作为参数传递:
navigate("Screen", {
onNavigateBack: this.handleOnNavigateBack
});
handleOnNavigateBack = () => {//do something};
在儿童屏幕上
this.props.navigation.state.params.onNavigateBack();
this.props.navigation.goBack();
即使您在屏幕之间导航,React-navigation 也会保持组件挂载。您可以使用该组件对这些事件做出反应:
<NavigationEvents
onDidFocus={() => console.log('hello world')}
/>
有关此组件的更多信息here。
如果有人在 2019 年来这里,试试这个:
import {NavigationEvents} from 'react-navigation';
将组件添加到渲染中:
<NavigationEvents onDidFocus={() => console.log('I am triggered')} />
现在,尽管来自 goBack() 或 navigate,但每次页面获得焦点时都会触发此 onDidFocus 事件。
您想在每次使用 drawernavigator
或 stacknavigator
导航到组件后执行某些操作;为此,NavigationEvents
比 componentDidMount
更合适。
import {NavigationEvents} from "react-navigation";
<NavigationEvents onDidFocus={()=>alert("Hello, I'm focused!")} />
注意:如果您想在使用抽屉导航或堆栈导航关注组件后每次都执行任务,则使用 NavigationEvents
是更好的主意。但是如果你想完成一次任务,那么你需要使用 componenetDidMount
。
如果使用 NavigationEvents 组件的 upvoted 语法不起作用,您可以尝试这样做:
// no need to import anything more
// define a separate function to get triggered on focus
onFocusFunction = () => {
// do some stuff on every screen focus
}
// add a focus listener onDidMount
async componentDidMount () {
this.focusListener = this.props.navigation.addListener('didFocus', () => {
this.onFocusFunction()
})
}
// and don't forget to remove the listener
componentWillUnmount () {
this.focusListener.remove()
}
React-navigation 文档explicitly described this case:
Consider a stack navigator with screens A and B. After navigating to
A, its componentDidMount is called. When pushing B, its
componentDidMount is also called, but A remains mounted on the stack
and its componentWillUnmount is therefore not called.
When going back from B to A, componentWillUnmount of B is called, but
componentDidMount of A is not because A remained mounted the whole
time.
现在有 3 个解决方案:
Subscribing to lifecycle events
...
React Navigation emits events to screen components that subscribe to
them. There are four different events that you can subscribe to:
willFocus
, willBlur
, didFocus
and didBlur
. Read more about them in the
API reference.
Many of your use cases may be covered with the withNavigationFocus
higher-order-component, the <NavigationEvents />
component, or the
useFocusState
hook.
withNavigationFocus
高阶分量
import React from 'react';
import { Text } from 'react-native';
import { withNavigationFocus } from 'react-navigation';
class FocusStateLabel extends React.Component {
render() {
return <Text>{this.props.isFocused ? 'Focused' : 'Not focused'}</Text>;
}
}
// withNavigationFocus returns a component that wraps FocusStateLabel and passes
// in the navigation prop
export default withNavigationFocus(FocusStateLabel);
<NavigationEvents />
分量
import React from 'react';
import { View } from 'react-native';
import { NavigationEvents } from 'react-navigation';
const MyScreen = () => (
<View>
<NavigationEvents
onWillFocus={payload => console.log('will focus', payload)}
onDidFocus={payload => console.log('did focus', payload)}
onWillBlur={payload => console.log('will blur', payload)}
onDidBlur={payload => console.log('did blur', payload)}
/>
{/*
Your view code
*/}
</View>
);
export default MyScreen;
useFocusState 钩子
首先安装库yarn add react-navigation-hooks
import { useNavigation, useNavigationParam, ... } from 'react-navigation-hooks'
function MyScreen() { const focusState = useFocusState(); return <Text>{focusState.isFocused ? 'Focused' : 'Not Focused'}</Text>; }
这是我的个人解决方案,使用 onDidFocus()
和 onWillFocus()
仅在从您的 API:
获取数据时呈现
import React, { PureComponent } from "react";
import { View } from "react-native";
import { NavigationEvents } from "react-navigation";
class MyScreen extends PureComponent {
state = {
loading: true
};
componentDidMount() {
this._doApiCall();
}
_doApiCall = () => {
myApiCall().then(() => {
/* Do whatever you need */
}).finally(() => this.setState({loading: false}));
};
render() {
return (
<View>
<NavigationEvents
onDidFocus={this._doApiCall}
onWillFocus={() => this.setState({loading: true})}
/>
{!this.state.loading && /*
Your view code
*/}
</View>
);
}
}
export default MyScreen;
根据react-navigation docs我们可以使用如下
componentDidMount () {
this.unsubscribe= this.props.navigation.addListener('focus', () => {
//Will execute when screen is focused
})
}
componentWillUnmount () {
this.unsubscribe()
}
类似于 vitosorriso 的答案,但应根据文档将 didFocus 更改为焦点
//na pagina que você quer voltar
import {NavigationEvents} from 'react-navigation';
async atualizarEstado() {
this.props.navigation.setParams({
number: await AsyncStorage.getItem('count'),
});}
render() {
return (
<View style={styles.container}>
<NavigationEvents onDidFocus={() => this.atualizarEstado()} />
</View>
);
}
2020 年解决方案 / React Navigation v5
在屏幕的 ComponentDidMount 中
componentDidMount() {
this.props.navigation.addListener('focus', () => {
console.log('Screen.js focused')
});
}
https://reactnavigation.org/docs/navigation-events/
或者:将 addListener 方法放在构造函数中以防止重复调用
https://reactnavigation.org/docs/navigation-events/
useEffect(() => {
const unsubscribe = props.navigation.addListener('focus', () => {
// do something
// Your apiCall();
});
return unsubscribe;
}, [props.navigation]);
我遇到过这个问题,问题是当你导航一个页面时,它第一次调用构造函数、componentWillmount、render componentDidmount,
但是在第二次导航到同一页面时它只调用渲染,所以如果你做任何 API 调用或来自 componentDidmount 的东西它不会被调用,
而且从未调用过 componentWillunmount。
你可以用这个方法,如果你使用react-navigation 5.x和class组件,它可以解决你的问题。
为每个 class 组件页面添加此方法并从构造函数中调用此方法一次
constructor(props) {
super(props);
this.state = {
...
};
...
this.navigationEventListener(); // call the function
}
navigationEventListener = () => { // add this function
let i = 0;
const initialState = this.state;
this.props.navigation.addListener('focus', () => {
if (i > 0) {
this.setState(initialState, () => {
//this.UNSAFE_componentWillMount(); // call componentWillMount
this.componentDidMount(); // call componentDidMount
});
}
});
this.props.navigation.addListener('blur', () => {
this.componentWillUnmount(); //call componentWillUnmount
++i;
});
}
我正在使用 stackNavigator
在屏幕之间导航。我在第二个 activity 中调用 componentDidMount()
函数中的两个 API。当我第一次加载它时,它加载成功。然后我按后退按钮返回到第一个 activity。然后,如果我再次转到第二个 activity,则不会调用 API,我会收到渲染错误。我找不到任何解决方案。如有任何建议,我们将不胜感激。
在 React 中,componentDidMount 仅在组件处于 mounted.I 时被调用,认为您正在尝试做的是在返回 StackNavigator 时调用 API。当您在父屏幕上像这样调用导航时,您可以将回调函数作为参数传递:
navigate("Screen", {
onNavigateBack: this.handleOnNavigateBack
});
handleOnNavigateBack = () => {//do something};
在儿童屏幕上
this.props.navigation.state.params.onNavigateBack();
this.props.navigation.goBack();
即使您在屏幕之间导航,React-navigation 也会保持组件挂载。您可以使用该组件对这些事件做出反应:
<NavigationEvents
onDidFocus={() => console.log('hello world')}
/>
有关此组件的更多信息here。
如果有人在 2019 年来这里,试试这个:
import {NavigationEvents} from 'react-navigation';
将组件添加到渲染中:
<NavigationEvents onDidFocus={() => console.log('I am triggered')} />
现在,尽管来自 goBack() 或 navigate,但每次页面获得焦点时都会触发此 onDidFocus 事件。
您想在每次使用 drawernavigator
或 stacknavigator
导航到组件后执行某些操作;为此,NavigationEvents
比 componentDidMount
更合适。
import {NavigationEvents} from "react-navigation";
<NavigationEvents onDidFocus={()=>alert("Hello, I'm focused!")} />
注意:如果您想在使用抽屉导航或堆栈导航关注组件后每次都执行任务,则使用 NavigationEvents
是更好的主意。但是如果你想完成一次任务,那么你需要使用 componenetDidMount
。
如果使用 NavigationEvents 组件的 upvoted 语法不起作用,您可以尝试这样做:
// no need to import anything more
// define a separate function to get triggered on focus
onFocusFunction = () => {
// do some stuff on every screen focus
}
// add a focus listener onDidMount
async componentDidMount () {
this.focusListener = this.props.navigation.addListener('didFocus', () => {
this.onFocusFunction()
})
}
// and don't forget to remove the listener
componentWillUnmount () {
this.focusListener.remove()
}
React-navigation 文档explicitly described this case:
Consider a stack navigator with screens A and B. After navigating to A, its componentDidMount is called. When pushing B, its componentDidMount is also called, but A remains mounted on the stack and its componentWillUnmount is therefore not called.
When going back from B to A, componentWillUnmount of B is called, but componentDidMount of A is not because A remained mounted the whole time.
现在有 3 个解决方案:
Subscribing to lifecycle events
...
React Navigation emits events to screen components that subscribe to them. There are four different events that you can subscribe to:
willFocus
,willBlur
,didFocus
anddidBlur
. Read more about them in the API reference.Many of your use cases may be covered with the
withNavigationFocus
higher-order-component, the<NavigationEvents />
component, or theuseFocusState
hook.
withNavigationFocus
高阶分量
import React from 'react';
import { Text } from 'react-native';
import { withNavigationFocus } from 'react-navigation';
class FocusStateLabel extends React.Component {
render() {
return <Text>{this.props.isFocused ? 'Focused' : 'Not focused'}</Text>;
}
}
// withNavigationFocus returns a component that wraps FocusStateLabel and passes
// in the navigation prop
export default withNavigationFocus(FocusStateLabel);
<NavigationEvents />
分量
import React from 'react';
import { View } from 'react-native';
import { NavigationEvents } from 'react-navigation';
const MyScreen = () => (
<View>
<NavigationEvents
onWillFocus={payload => console.log('will focus', payload)}
onDidFocus={payload => console.log('did focus', payload)}
onWillBlur={payload => console.log('will blur', payload)}
onDidBlur={payload => console.log('did blur', payload)}
/>
{/*
Your view code
*/}
</View>
);
export default MyScreen;
useFocusState 钩子
首先安装库yarn add react-navigation-hooks
import { useNavigation, useNavigationParam, ... } from 'react-navigation-hooks'
function MyScreen() { const focusState = useFocusState(); return <Text>{focusState.isFocused ? 'Focused' : 'Not Focused'}</Text>; }
这是我的个人解决方案,使用 onDidFocus()
和 onWillFocus()
仅在从您的 API:
import React, { PureComponent } from "react";
import { View } from "react-native";
import { NavigationEvents } from "react-navigation";
class MyScreen extends PureComponent {
state = {
loading: true
};
componentDidMount() {
this._doApiCall();
}
_doApiCall = () => {
myApiCall().then(() => {
/* Do whatever you need */
}).finally(() => this.setState({loading: false}));
};
render() {
return (
<View>
<NavigationEvents
onDidFocus={this._doApiCall}
onWillFocus={() => this.setState({loading: true})}
/>
{!this.state.loading && /*
Your view code
*/}
</View>
);
}
}
export default MyScreen;
根据react-navigation docs我们可以使用如下
componentDidMount () {
this.unsubscribe= this.props.navigation.addListener('focus', () => {
//Will execute when screen is focused
})
}
componentWillUnmount () {
this.unsubscribe()
}
类似于 vitosorriso 的答案,但应根据文档将 didFocus 更改为焦点
//na pagina que você quer voltar
import {NavigationEvents} from 'react-navigation';
async atualizarEstado() {
this.props.navigation.setParams({
number: await AsyncStorage.getItem('count'),
});}
render() {
return (
<View style={styles.container}>
<NavigationEvents onDidFocus={() => this.atualizarEstado()} />
</View>
);
}
2020 年解决方案 / React Navigation v5
在屏幕的 ComponentDidMount 中
componentDidMount() {
this.props.navigation.addListener('focus', () => {
console.log('Screen.js focused')
});
}
https://reactnavigation.org/docs/navigation-events/
或者:将 addListener 方法放在构造函数中以防止重复调用
https://reactnavigation.org/docs/navigation-events/
useEffect(() => {
const unsubscribe = props.navigation.addListener('focus', () => {
// do something
// Your apiCall();
});
return unsubscribe;
}, [props.navigation]);
我遇到过这个问题,问题是当你导航一个页面时,它第一次调用构造函数、componentWillmount、render componentDidmount, 但是在第二次导航到同一页面时它只调用渲染,所以如果你做任何 API 调用或来自 componentDidmount 的东西它不会被调用,
而且从未调用过 componentWillunmount。
你可以用这个方法,如果你使用react-navigation 5.x和class组件,它可以解决你的问题。
为每个 class 组件页面添加此方法并从构造函数中调用此方法一次
constructor(props) {
super(props);
this.state = {
...
};
...
this.navigationEventListener(); // call the function
}
navigationEventListener = () => { // add this function
let i = 0;
const initialState = this.state;
this.props.navigation.addListener('focus', () => {
if (i > 0) {
this.setState(initialState, () => {
//this.UNSAFE_componentWillMount(); // call componentWillMount
this.componentDidMount(); // call componentDidMount
});
}
});
this.props.navigation.addListener('blur', () => {
this.componentWillUnmount(); //call componentWillUnmount
++i;
});
}