在 goBack() 上刷新上一个屏幕

Refresh previous screen on goBack()

我是 React Native 的新手。我们如何在通过调用 goBack() 返回上一屏幕时 refresh/reload?

假设我们有 3 个屏幕 A、B、C:

A -> B -> C

当我们从屏幕 C 运行 goBack() 返回到屏幕 B 但使用旧的 state/data。我们如何刷新它?构造函数不会被第二次调用。

如果您尝试将新数据导入到先前的视图中,但它不起作用,您可能需要重新审视您将数据传输到该视图中的方式。调用 goBack 不应影响先前组件的安装,并且可能不会像您注意到的那样再次调用其构造函数。

作为第一步,我会问您是否使用 Component, PureComponent, or Functional Component。根据您的构造函数评论,听起来您正在扩展一个组件 class.

如果您使用的是组件,则渲染方法受制于 shouldComponentUpdate 并且您的状态值由您控制。

我建议使用 componentWillReceiveProps 来验证组件正在接收新数据,并确保其状态已更新以反映新数据。

如果您使用构造函数调用 API 或某种异步函数,请考虑将该函数移动到您从中调用 goBack 的路由和您要使用最新数据更新的组件。然后你可以要求你的父组件重新查询 API,或者从子组件更新它的状态。

如果路由 C 更新应用程序的 "state/data",则该更新应传播到路由 A、B 和 C 的共享父级,然后作为 prop 向下传递。

或者,您可以使用像 Redux 这样的状态管理解决方案来维护独立于 parent/child 组件的状态 - 您可以将组件包装在 connect 高阶组件中以在应用程序状态发生变化时获取最新更新。

TL;DR 最终听起来您的问题的答案在于您的应用程序状态的存储位置。它应该存储在组件层次结构中足够高的位置,以便每个路由始终接收从其父级传递的最新数据作为 prop。

这个答案假设正在使用 react-native-navigation 库,这不太可能,因为它实际上没有 goBack() 方法...

构造函数不会调用第二次,因为屏幕 A 和 B 仍在呈现(但隐藏在屏幕 C 后面)。如果您需要知道屏幕 B 何时再次可见,您可以收听 navigation events.

class ScreenB extends Component {
  constructor(props) {
    super(props);
    // Listen to all events for screen B
    this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent);
  }

  onNavigatorEvent = event => {
    switch (event.id) {
      case 'willAppear':
        // refresh your state...
        break;
  };
}

其他活动:willDisappeardidAppeardidDisappear

您的问题的另一种解决方案是使用像 Redux 这样的状态管理解决方案,在更新时为所有屏幕提供状态(而不是仅仅在屏幕转换上。参见 old react-native-nav/redux example

是的,构造函数只被第一次调用,不能调用两次。

First: 但是你可以把数据getter/setter从构造函数中分离出来放在一个函数中,这样你就可以把函数传给下一个Scene并且无论何时返回,您都可以简单地回忆起该功能。

更好: 你可以在你的第一个场景中做一个返回函数,它在返回的同时也会更新场景,并将返回函数向下传递。这样第二个场景就不会知道你的update函数是合理的。

最佳:您可以在第二个场景中使用 redux 并分派一个返回操作。然后在你的减速器中你负责返回并刷新你的场景。

在要返回的屏幕中的焦点回调中添加 Api 调用可解决问题。

componentDidMount() {
    this.props.fetchData();
    this.willFocusSubscription = this.props.navigation.addListener(
      'willFocus',
      () => {
        this.props.fetchData();
      }
    );
  }

  componentWillUnmount() {
    this.willFocusSubscription.remove();
  }

2021 年更新:

  componentDidMount() {
    this.props.fetchData();
    this.willFocusSubscription = this.props.navigation.addListener(
      'willFocus',
      () => {
        this.props.fetchData();
      }
    );
  }

  componentWillUnmount() {
    this.willFocusSubscription();
  }

如果你使用 React Hook:

  React.useEffect(() => {
      fetchData();
      const willFocusSubscription = props.navigation.addListener('focus', () => {
        fetchData();
    });

    return willFocusSubscription;
}, []);

在您的屏幕上,B 构造函数将像魔术一样工作:)

    this.props.navigation.addListener(
          'didFocus',
          payload => {
            this.setState({is_updated:true});
          }
    );

React-Navigation 自带的内置监听函数是最简单的解决方案。每当通过向后导航再次打开组件 'focused' 时,侦听器就会触发。通过编写一个在加载组件时和通知侦听器时都可以调用的 loadData 函数,您可以在返回时轻松地重新加载数据。

   componentWillMount(){
    this._subscribe = this.props.navigation.addListener('didFocus', () => {
     this.LoadData();
     //Put your Data loading function here instead of my this.LoadData()
    });}

感谢@Bat。 我花了很多时间寻找答案,最后,我得到了一个根据我的需要工作的基本解决方案。不过我很担心。 只需在您之前的 activity 中创建一个类似的函数,确保绑定它。

    changeData(){
    var mydata= salesmanActions.retrieveAllSalesman();
    this.setState({dataListFill: mydata});
    alert('' + mydata.length);
    }

简单,然后在构造函数中绑定这个,

    this.changeData= this.changeData.bind(this);

之后,由于我使用的是react native navigation,所以我会像下面的代码一样将这个函数简单地传递给第二个屏幕:

    onPress={() => this.props.navigation.navigate('Add Salesman', {doChange: 
    this.changeData} )}

所以当注册为"Add Salesman"的新屏幕被调用时,一个名为"doChange"的参数分配了一个功能也会被传递到其他屏幕。 现在,在其他屏幕的任何地方调用此方法,方法是:

    this.props.route.params.doChange();

对我有用。我希望对你也有用,感谢 @Bat 的想法。

使用 useIsFocused 钩子怎么样?

https://reactnavigation.org/docs/function-after-focusing-screen/#re-rendering-screen-with-the-useisfocused-hook

const componentB = (props) => { 
  // check if screen is focused
  const isFocused = useIsFocused();

  // listen for isFocused, if useFocused changes 
  // call the function that you use to mount the component.

  useEffect(() => {
    isFocused && updateSomeFunction()
  },[isFocused]);
}

我也有类似的情况,我刷新的方式是在按下后退按钮时重新设置路线。所以,当按下后退按钮时,屏幕会重新被压入堆栈,我屏幕上的 useEffect 会加载数据

navigation.reset({
  index: 0,
  routes: [{ name: "SCREEN WHERE THE GOBACK BUTTON SHOULD GO" }],
});

对于反应导航5.x使用

5.x

使用

componentDidMount() {
  this.loadData();

  this.focusListener = this.props.navigation.addListener('focus', () => {
    this.loadData();
    //Put your Data loading function here instead of my this.loadData()
  });
}

对于功能组件

function Home({ navigation }) {
  React.useEffect(() => {
    const unsubscribe = navigation.addListener('focus', () => {
      loadData();
      //Put your Data loading function here instead of my loadData()
    });

    return unsubscribe;
  }, [navigation]);

  return <HomeContent />;
}

更新 react-navigation v5 并使用 React Hooks。其实用法和react base是一样的class。有关详细信息,请查看文档 here

示例代码如下:

function Profile({ navigation }) {
  React.useEffect(() => {
    const unsubscribe = navigation.addListener('focus', () => {
      // do something
    });

    return unsubscribe;
  }, [navigation]);

  return <ProfileContent />;
}

如上代码,我们在变量导航发生变化时添加事件监听器,然后我们执行类似调用函数 refresh() 的操作,最后,我们 return 用于删除事件监听器的函数。简单!

 let we have 2 screen A and B , screen A showing all data . and screen B is responsible for adding that data. we add some data on using screen B and want to show instant changes on Screen A . we use below code in A   

    componentDidMount(){
                this.focusListener = this.props.navigation.addListener('focus', () => {
                thi`enter code here`s.startData();
                //Put your Data loading function here
            }); 
    }

我认为我们有一个非常简单的方法(可以在 2021 年使用)来做到这一点。而不是使用 goBacknavigate,您应该使用 push

this.props.navigation.push('your_route_B'). 

你也可以像我们传入的方式一样传递参数navigate

b/w navigatepush 的唯一区别是 navigate 检查我们正在传递的路由是否存在于堆栈中。因此将我们带到旧的,但是 push 只是将我们发送到那里而不检查它是否在堆栈中(即,是否早些时候访问过该路由。)

对于 React 导航 (5.x),您只需要添加一个焦点订阅并将您的组件初始化逻辑放在一个单独的函数中,如下所示:

componentDidMount() {

    this.init();

    this.didFocusSubscription = this.props.navigation.addListener(
      'focus',
      () => {
        this.init();
      }
    );


  }


init = async () => {
   //fetch some data and set state here
   
  }

简单!在 useFocusEffect(func)

中插入函数
import { useFocusEffect } from '@react-navigation/native' 

这可以通过 useFocusEffect'@react-navigation/native'

实现

useFocusEffect 会在每次屏幕聚焦时生效

参考:https://reactnavigation.org/docs/use-focus-effect/

import { useFocusEffect } from '@react-navigation/native';

function Profile({ }) {
  
  useFocusEffect(
    React.useCallback(() => {
      //Below alert will fire every time when profile screen is focused
        alert('Hi from profile')
    }, [])
  );

  return // ...code ;
}