52

我是 React Native 的新手。通过调用返回时,我们如何刷新/重新加载上一个屏幕goBack()

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

A -> B -> C

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

4

15 回答 15

85

在您要返回的屏幕中的焦点回调中添加 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;
}, []);
于 2018-06-22T08:37:56.923 回答
42

使用 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]);
}
于 2020-05-23T17:06:02.097 回答
22

对于 react-navigation 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 />;
}
于 2020-07-27T18:21:31.697 回答
16

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

    this.props.navigation.addListener(
          'didFocus',
          payload => {
            this.setState({is_updated:true});
          }
    );
于 2018-10-17T13:33:31.150 回答
8

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

首先:但是您可以将数据 getter/setter 与构造函数分开并将其放入一个函数中,这样您就可以将函数传递给下一个场景,并且无论何时返回,您都可以简单地调用该函数。

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

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

于 2017-10-23T14:53:29.370 回答
5

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

   componentWillMount(){
    this._subscribe = this.props.navigation.addListener('didFocus', () => {
     this.LoadData();
     //Put your Data loading function here instead of my this.LoadData()
    });}
于 2018-11-18T20:07:47.100 回答
3

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

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

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

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

于 2021-01-24T10:40:49.937 回答
2

更新 react-navigation v5 并使用 React Hooks。其实和react基类的用法是一样的。有关更多详细信息,请在此处查看文档

这是示例代码:

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

    return unsubscribe;
  }, [navigation]);

  return <ProfileContent />;
}

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

于 2020-10-08T07:02:45.663 回答
1

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

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

于 2020-05-29T02:12:35.330 回答
1

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

componentDidMount() {

    this.init();

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


  }


init = async () => {
   //fetch some data and set state here
   
  }
于 2021-01-28T22:54:27.173 回答
1

简单的!在里面插入函数useFocusEffect(func)

import { useFocusEffect } from '@react-navigation/native' 
于 2021-06-21T05:50:25.893 回答
0

如果您正在尝试将新数据导入先前的视图,但它不起作用,您可能需要重新审视将数据导入该视图的方式。调用goBack不应影响先前组件的安装,并且可能不会再次调用其构造函数,正如您所指出的。

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

如果您使用的是组件,则 render 方法受shouldComponentUpdate的约束,并且您的状态值在您的控制中。

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

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

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

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

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

于 2017-09-30T17:26:10.197 回答
0

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

构造函数没有第二次调用,因为屏幕 A 和 B 仍被渲染(但隐藏在屏幕 C 后面)。如果您需要知道屏幕 B 何时再次可见,您可以收听导航事件

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

其他事件:willDisappear, didAppear,didDisappear

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

于 2017-10-01T05:02:31.773 回答
0

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

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

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

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

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

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

因此,当注册为“Add Salesman”的新屏幕将被调用时,分配了功能的名为“doChange”的参数也将被转移到其他屏幕。现在,在其他屏幕上通过以下方式在任何地方调用此方法:

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

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

于 2020-03-25T17:34:51.030 回答
0
 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
            }); 
    }
于 2020-12-15T14:30:15.197 回答