29

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

4

11 回答 11

52

如果有人在 2019 年来到这里,试试这个:

import {NavigationEvents} from 'react-navigation';

将组件添加到您的渲染中:

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

现在,这个 onDidFocus 事件将在每次页面获得焦点时触发,尽管来自 goBack() 或导航。

于 2018-11-20T07:04:27.830 回答
17

如果使用 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()
}
于 2019-05-01T21:13:51.073 回答
8

React-navigation 文档明确描述了这种情况

考虑一个带有屏幕 A 和 B 的堆栈导航器。导航到 A 后,它的 componentDidMount 被调用。在压入 B 时,它的 componentDidMount 也会被调用,但 A 仍然挂载在堆栈上,因此不会调用它的 componentWillUnmount。

从 B 回到 A 时,调用了 B 的 componentWillUnmount,但 A 的 componentDidMount 没有被调用,因为 A 一直处于挂载状态。

现在有3个解决方案:

订阅生命周期事件

...

React Navigation 向订阅它们的屏幕组件发出事件。您可以订阅四种不同的事件 :willFocuswillBlur和。在 API 参考中阅读有关它们的更多信息。didFocusdidBlur

您的许多用例可能都包含在withNavigationFocus 高阶组件、<NavigationEvents />组件或 useFocusState钩子中。

  1. 高阶withNavigationFocus 分量
  2. 组件_<NavigationEvents />
  3. 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 />零件

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

这是我的个人解决方案,仅在从您的 API 获取数据时使用onDidFocus()onWillFocus()呈现:

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;
于 2019-12-19T09:45:19.947 回答
4

即使您在屏幕之间导航,React-navigation 也会保持组件挂载。您可以使用该组件对这些事件做出反应:

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

有关此组件的更多信息,请点击此处

于 2018-10-30T10:16:17.733 回答
4

2020 年解决方案 / React Navigation v5

在屏幕的 ComponentDidMount 内

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

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

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

于 2020-06-28T19:23:43.510 回答
2

根据反应导航文档,我们可以使用如下

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

componentWillUnmount () {
  this.unsubscribe()
}

类似于 vitosorriso 的答案,但应该根据文档将 didFocus 更改为焦点

于 2020-05-20T16:36:19.107 回答
1

您希望在每次使用drawernavigatoror导航到组件后执行某些操作stacknavigator ;为此目的NavigationEvents,比componentDidMount .

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

注意 :如果您想在每次使用抽屉导航或堆栈导航关注组件后执行任务,那么使用NavigationEvents是更好的主意。但是,如果您想执行一次任务,则需要使用componenetDidMount .

于 2019-01-28T17:01:13.117 回答
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>
);
}
于 2020-05-28T14:05:41.083 回答
0

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

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

return unsubscribe;
    
}, [props.navigation]);
于 2021-01-31T16:33:12.053 回答
0

我遇到过这个问题,问题是当你导航一个页面时,第一次调用构造函数、componentWillmount、render componentDidmount,但是第二次导航到同一页面时它只调用render,所以如果你做任何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;
        });
    }
于 2021-06-15T13:54:02.333 回答
-1

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

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

在儿童屏幕上

this.props.navigation.state.params.onNavigateBack();
this.props.navigation.goBack();
于 2017-12-29T08:38:26.023 回答