导航后不调用`componentDidMount()`函数

时间:2017-12-29 05:55:47

标签: android reactjs react-native stack-navigator

我正在使用stackNavigator在屏幕之间导航。我在第二个活动中在componentDidMount()函数中调用了两个API。当我第一次加载它时,它会成功加载。然后我按回按钮返回第一个活动。然后,如果我再次进行第二次活动,则不会调用API,我会收到渲染错误。我无法找到任何解决方案。任何建议将不胜感激。

11 个答案:

答案 0 :(得分:16)

如果有人在2019年到这里来,请尝试以下操作:

import {NavigationEvents} from 'react-navigation';

将组件添加到渲染中:

<NavigationEvents onDidFocus={() => console.log('I am triggered')} />

现在,尽管页面来自goBack()或导航,但每次页面聚焦时都会触发此onDidFocus事件。

答案 1 :(得分:4)

2020年解决方案/ React Navigation v5

在屏幕的ComponentDidMount内部

componentDidMount() {
    this.props.navigation.addListener('focus', () => {
      console.log('Screen.js focused')
    });
}

https://reactnavigation.org/docs/navigation-events/

或者:将addListener方法放在构造函数中,以防止重复调用

答案 2 :(得分:2)

根据react-navigation docs,我们可以如下使用

componentDidMount () {
  this.unsubscribe= this.props.navigation.addListener('focus', () => {
    //Will execute when screen is focused
  })
}

componentWillUnmount () {
  this.unsubscribe()
}

类似于vitosorriso的回答,但应更改didFocus以根据文档进行关注

答案 3 :(得分:1)

即使在屏幕之间导航,反应导航也会使组件保持安装状态。您可以使用该组件对这些事件做出反应:

<NavigationEvents
  onDidFocus={() => console.log('hello world')}
/>

有关此组件here的更多信息。

答案 4 :(得分:1)

如果使用NavigationEvents组件的升级语法不起作用,则可以尝试以下操作:

// 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()
}

答案 5 :(得分:1)

React导航文档explicitly described this case

  

考虑一个带有屏幕A和B的堆栈导航器。导航到   A,其componentDidMount被调用。推B时   componentDidMount也被调用,但是A仍然安装在堆栈上   因此它的componentWillUnmount不会被调用。

     

从B返回A时,会调用B的componentWillUnmount,但是   A的componentDidMount并不是因为A保持整个安装状态   时间。

现在有3种解决方案:

  

订阅生命周期事件

     

...

     

反应导航向订阅的屏幕组件发出事件   他们。您可以订阅四个不同的事件:    startTimer() { this.servicesService.startTimer(); this.currentState = this.servicesService.getCurrentState(); } pauseTimer() { this.servicesService.pauseTimer(); this.currentState = this.servicesService.getCurrentState(); } willFocuswillBlurdidFocus。在中阅读有关它们的更多信息   API参考。

     

didBlur可能涵盖了许多用例   高阶成分,withNavigationFocus成分或   <NavigationEvents />钩子。

  1. withNavigationFocus higher-order-component
  2. <NavigationEvents /> component
  3. useFocusState hook已弃用

useFocusState     高阶分量

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 />

useFocusState挂钩

第一个安装库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;

yarn add react-navigation-hooks

这是我的个人解决方案,仅当从您的API中提取数据时,才使用import { useNavigation, useNavigationParam, ... } from 'react-navigation-hooks' function MyScreen() { const focusState = useFocusState(); return <Text>{focusState.isFocused ? 'Focused' : 'Not Focused'}</Text>; } onDidFocus()进行渲染:

onWillFocus()

答案 6 :(得分:1)

//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>
);
}

答案 7 :(得分:0)

在React中,仅在安装组件时才调用componentDidMount。我认为您要做的是在StackNavigator中返回时调用您的API。在父屏幕上调用如此导航时,您可以将回调函数作为参数传递:

  navigate("Screen", {
     onNavigateBack: this.handleOnNavigateBack
  }); 
  handleOnNavigateBack = () => {//do something};

在儿童屏幕上

this.props.navigation.state.params.onNavigateBack();
this.props.navigation.goBack();

答案 8 :(得分:0)

您想在每次使用drawernavigatorstacknavigator导航到组件后执行一些操作;为此,NavigationEventscomponentDidMount更合适。

import {NavigationEvents} from "react-navigation";
<NavigationEvents onDidFocus={()=>alert("Hello, I'm focused!")} />

注意 :如果要在使用抽屉式导航或堆栈导航将焦点放在组件上之后每次执行任务,那么最好使用NavigationEvents。但是,如果您想执行一次任务,则需要使用componenetDidMount

答案 9 :(得分:0)

https://reactnavigation.org/docs/navigation-events/

useEffect(() => {       
            
    const unsubscribe = props.navigation.addListener('focus', () => {
        // do something
        // Your apiCall();
    });

return unsubscribe;
    
}, [props.navigation]);

答案 10 :(得分:0)

我遇到过这个问题,问题是当你浏览一个页面时,它第一次调用构造函数,componentWillmount,render componentDidmount, 但是在第二次导航到同一页面时,它只会调用渲染,因此如果您执行任何 API 调用或来自 componentDidmount 的某些内容,它将不会被调用,

还有 componentWillunmount 从未调用过。

您可以使用这种方法,如果您使用带有类组件的 react-navigation 5.x,它可以解决您的问题。

为每个类组件页面添加此方法并从构造函数调用一次此方法

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;
        });
    }