从不同导航器(React Native)的另一个屏幕返回时如何刷新屏幕?

How to refresh a screen when returning from another screen of a different navigator (React Native)?

我一直在使用 StackNavigator 实现我的大部分应用程序。现在,我添加了一个 DrawerNavigator,它的一个屏幕从中调用原始 StackNavigator 的另一个屏幕。例如,考虑以下用户可以进行的导航序列:

ScreenA -> ScreenB -> ScreenC

其中ScreenA属于StackNavigator,ScreenB属于DrawerNavigator,ScreenC又属于StackNavigator。为实现这一点,实际上 ScreenA 并不直接调用 ScreenB,而是调用另一个屏幕,其唯一目的是充当属于 DrawerNavigator 的所有屏幕的根。此外,该根在 ScreenProps 中接收 StackNavigator,以便其屏幕稍后可以再次使用 Stack。

现在,如果我在 ScreenC 中并使用“this.props.navigation.goBack()”返回,我会 return 到 ScreenB 中的 DrawerNavigator,因为它称为 ScreenC。 ScreenB 应该刷新其状态,即它应该从数据库重新加载信息,因为该信息可能在 ScreenC 中已更改,因此先前的状态不再有效。

当只使用 StackNavigator 时,我总是设法使用“NavigationEvents”来完成。例如:

import {Component} from 'react'
...
import { NavigationEvents } from 'react-navigation'

class ScreenB extends Component{

    // This is the function that loads information from the database (PouchDB)
    loadInformation = async() =>{
        ...
    }

    render(){
        return(
            <View>
                <NavigationEvents onWillFocus = {payload => this.loadInformation()}/>
                <NavigationEvents onDidFocus  = {payload => this.loadInformation()}/>
                ...
            </View>
        )
    }
}

通过此实现,“loadInformation”功能在我第一次进入屏幕时以及在我从子屏幕return访问它时都被激活。但是这次我混合了两个导航器,当 return 从 ScreenC 到 ScreenB 时,“onWillFocus”和“onDidFocus”都没有激活,所以我无法再次进入“loadInformation”功能。我该怎么做?

编辑:

我还尝试在 Redux 存储中保留一个布尔变量,用于确定是否必须激活 ScreenB 的“loadInformation”功能。该变量以真值开头。然后,一旦我进入屏幕 B 并执行该功能,它就会更改为 false。当我导航到 ScreenC 时,在该屏幕中变量再次更改为 true,因此当我返回到 ScreenB 时它再次指示必须执行该函数。

需要在 ScreenB 中使用“componentDidUpdate”函数,该函数会不断检查该变量是真还是假,以便调用“loadInformation”。这解决了问题,但带来了新的问题。当我尝试从 ScreenB 导航到 DrawerNavigator 的另一个屏幕时,它花费了太多时间,因为在转换中重复调用“componentDidUpdate”。所以这个解决方案似乎不可行。

很遗憾,您使用的方法 <NavigationEvents> 已更新。所以,你应该做的是:

class screenA/ screenB/ screenC extends React.Component {
  componentDidMount() {
    this._unsubscribe = navigation.addListener('focus', () => {
      // do something
    });
  }

  componentWillUnmount() {
    this._unsubscribe();
  }

  render() {
    // Content of the component
  }
}

在您的所有屏幕中使用这些更新的导航事件。希望它能解决您的问题。更多信息See This

我正在回答我自己的问题。

解决方案是使用 Redux 商店中的布尔变量来指示是否必须激活函数“loadInformation”。假设变量名为“loadView”,默认值为“false”,但 ScreenC 在将要关闭时将其设置为“true”,因此我们将 return 转到 ScreenB。

换句话说,ScreenC的文件包含这段代码:

import {Component} from 'react'
import { connect } from 'react-redux'
// Here we import the action that allows to change the value of "loadView"
import { changeLoadView } from '../../redux/actions/popUpActions'
...

class ScreenC extends Component{
    ...
    // Function that is activated automatically when we leave the screen
    componentWillUnmount(){
        // This is the function that assigns the value "true" to "loadView"
        this.props.dispatchChangeLoadView(true)
    }
    ...
}

const mapStateToProps = (state) => {
    return {
        ...
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
        dispatchChangeLoadView: (bool) => dispatch(changeLoadView(bool)),
        ....
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(ScreenC);

在 ScreenB 的文件中我使用了一个“假视图”,它是一个没有直接放在“渲染”函数中但被另一个函数调用的 React 视图(在这种情况下名为“activateLoadInformation”) .该函数 return 是一个空视图,但使用它的原因是因为在它的“return”之前我们可以激活我们想要的 ScreenB 的任何其他函数,在本例中是“loadInformation”。我不知道另一种激活函数的方法,这些函数不会在我们想要的时候任意渲染任何东西。

import {Component} from 'react'
import { connect } from 'react-redux'
...

class ScreenB extends Component{
    ...
    // This is the function that loads information from the database (PouchDB)
    loadInformation = async() =>{
        this.props.dispatchChangeLoadView(false);
        ...
    }

    // Fake view that calls the function "loadInformation"
    activateLoadInformation(){
        this.loadInformation();
        return(<View/>)
    }

    render(){
        return(
            <View>
                {!this.props.loadView && 
                    <NavigationEvents onWillFocus = {payload => this.loadInformation()}/>
                }
                {this.props.loadView &&
                    this.activateLoadInformation()
                }
                ...
            </View>
        )
    }
}

const mapStateToProps = (state) => {
    return {
        loadView: state.popUpReducer.loadView,
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
        dispatchChangeLoadView: (bool) => dispatch(changeLoadView(bool)),
        ....
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(ScreenB);