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

时间:2017-09-30 16:18:05

标签: react-native react-router react-native-android react-native-ios react-native-navigation

我是React Native的新手。如何通过调用goBack()

返回前一屏幕时刷新/重新加载

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

A -> B -> C

当我们从屏幕C运行goBack()时,它返回到屏幕B但是具有旧状态/数据。我们怎样刷新它?构造函数不会被第二次调用。

16 个答案:

答案 0 :(得分:14)

在回叫中添加Api呼叫可以解决问题

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

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

答案 1 :(得分:7)

如何使用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(() => {
    updateSomeFunction()
  },[isFocused]);
}

答案 2 :(得分:4)

React-Navigation附带的内置侦听器功能将是最简单的解决方案。每当通过向后导航将某个组件再次“聚焦”到该组件时,侦听器就会触发。通过编写一个loadData函数,该函数既可以在加载组件时又可以在通知侦听器时被调用,从而可以轻松地在向后导航时重新加载数据。

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

答案 3 :(得分:3)

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

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

答案 4 :(得分:3)

对于react-navigation 5.x使用

5.x

使用

componentDidMount() {
        this.startData();

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

答案 5 :(得分:2)

我认为我们有一个非常简单的方法(在 2021 年有效)来做到这一点。您应该使用 goBack

而不是使用 navigatepush
this.props.navigation.push('your_route_B'). 

您也可以像我们传入 navigate 一样传递参数。

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

答案 6 :(得分:1)

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

第一个:但是您可以将数据getter / setter与构造函数分开并将其放在一个函数中,这样您就可以将函数传递给下一个场景,并且每当您执行此操作时回去你可能只是回想起这个功能。

更好:您可以在第一个场景中创建一个返回功能,该功能还会在返回时更新场景并向下传递返回功能。这样第二个场景就不会知道你的更新功能是否合理。

最佳:您可以使用redux并在第二个场景中发送回传动作。然后在您的减速机中,您将负责返回&刷新你的场景。

答案 7 :(得分:1)

我有类似的情况,刷新的方法是在按下后退按钮时重置路线。因此,发生的事情是,当按下后退按钮时,屏幕被重新推入堆栈,并且屏幕上的useEffect加载了数据

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

答案 8 :(得分:1)

更新react-navigation v5并使用React Hooks。实际上,它与react基类的用法相同。有关更多详细信息,请查阅文档here

这是示例代码:

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

    return unsubscribe;
  }, [navigation]);

  return <ProfileContent />;
}

如上面的代码,我们在变量导航更改的同时添加事件侦听器,然后执行诸如调用函数refresh()的操作,最后返回用于删除事件侦听器的函数。简单!

答案 9 :(得分:1)

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

componentDidMount() {

    this.init();

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


  }


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

答案 10 :(得分:0)

如果您尝试将新数据添加到以前的视图中,并且它不起作用,您可能需要重新审视将数据导入该视图的方式。调用goBack不会影响先前组件的安装,并且可能无法再次调用其构造函数。

作为第一步,我会问您是否正在使用ComponentPureComponentFunctional Component。根据您的构造函数注释,听起来您正在扩展Component类。

如果你正在使用某个组件,那么渲染方法必须以shouldComponentUpdate为准,并且你的状态值在你的控制范围内。

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

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

如果路由C更新&#34;状态/数据&#34;应用程序的更新应该传播到路由A,B和C的共享父级,然后作为prop传递下来。

或者,您可以使用状态管理解决方案(如Redux)来维护该状态,而不依赖于父/子组件 - 您可以将组件包装在connect更高阶的组件中以获取最新更新任何时候应用程序状态发生变化。

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

答案 11 :(得分:0)

这个答案假定正在使用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

答案 12 :(得分:0)

可悲的是,没有一个答案对我有用,但是我找到了一个简单的库,它可以完成相同的工作:

npm install --save react-native-event-listeners

componentDidMount() {
        this.listener = EventRegister.addEventListener('reloadData', (data) => {
            console.log("data is fetched");
            this.updateState(data); // private function that update the state using setState to trigger render
        });
    }

componentWillUnmount() {
    EventRegister.removeEventListener(this.listener)
}

在其他组件中,以我为例,它是一个不透明度按钮:

<TouchableOpacity
            onPress={() => {
                fetch('url').then(data => {
                    ServiceLocator.saveData('matba', data);
                    EventRegister.emit('reloadData', data);
                    props.nav.goBack()
                })
                    .catch(error =>{
                        console.log(error);
                        Alert.alert("Cannot connect to the server");
                        props.nav.goBack()
                    });
            }}
        >

答案 13 :(得分:0)

感谢@Bat。 我花了很多时间来寻找答案,最后,我得到了一个基本的解决方案,可以根据自己的需要进行工作。我当时很担心。 只需在上一个活动中使像这样的功能,确保将其绑定即可。

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

简单,然后在构造函数中将其绑定

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

此后,由于我正在使用本机导航,因此我将把此函数传递给第二个屏幕,就像下面的代码一样:

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

因此,当调用注册为“添加销售员”的新屏幕时,分配了功能的名为“ doChange”的参数也将传送到其他屏幕。 现在,在其他屏幕上,可以通过以下任何方式调用此方法:

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

对我有用。我希望也能为您服务,谢谢@Bat的想法。

答案 14 :(得分:0)

p4 unshelve -s <target-CL> <file1> <file2>

答案 15 :(得分:0)

简单!在 useFocusEffect(func)

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