【问题标题】:Refresh previous screen on goBack()在 goBack() 上刷新上一个屏幕
【发布时间】:2018-03-12 07:02:54
【问题描述】:

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

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

A -> B -> C

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

【问题讨论】:

  • 你有解决办法吗?请告诉我,我也面临同样的情况。我已经解决了。
  • 是的@DeepakSachdeva,谢谢,但您可以分享您的发现以获取知识。以下确实帮助了我stackoverflow.com/a/46892405/2086124
  • 不知道你是如何具体解决这个问题的,因为我也有同样的问题。您参考下面的答案,但用户@Bat 提出的三个选项中的哪一个?如果您回答自己的问题并详细说明如何解决问题,那也会好得多。因为,这真的会帮助那些将来遇到和你一样问题的人。希望你能发布它。上帝保佑。

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


【解决方案1】:

在您要返回的屏幕中的焦点回调中添加 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;
}, []);

【讨论】:

  • 这应该是答案。如果放入正确的屏幕(按下后退按钮时将显示屏幕),则可以完美运行。还包括未弃用的方法。好的! :)
  • MukundhanwillFocus会在goBack()之后自动启动吗?是否所有重新获取的数据都进入fetchData()
  • 是的,navigation 对象上的 addListenerwillFocus 事件成功了。谢谢!
  • 必须使用“焦点”才能使其正常工作。 “willFocus”和“didFocus”不起作用
  • 取消订阅时我必须this.willFocusSubscription(),如文档中所述:reactnavigation.org/docs/navigation-events/…
【解决方案2】:

使用 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]);
}

【讨论】:

  • 这是初学者最简单的方法。我不知道为什么这个答案不在顶部。
  • @rafwell 我不是初学者,但我喜欢答案的简单性。 ?
  • 为我工作,谢谢。我刚刚添加了useEffect(() => {isFocused && updateSomeFunction() },[isFocused]); 以仅在获得焦点时获取数据
  • 在这里的所有答案中,这是 2021 年唯一对我有用的答案。isFocused 钩子更新可靠 - 只要确保您检查钩子内它何时为真,如上面的评论所示。
【解决方案3】:

对于 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 />;
}

【讨论】:

  • 能否举个函数组件的例子?
  • 这是最干净最简单的解决方案。
  • 它正在工作,谢谢 this.props.navigation.addListener('focus', () => { this.loadData(); });
【解决方案4】:

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

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

【讨论】:

  • 你好兄弟,你能不能给我一个示例代码.. 我也面临这个问题。
  • @RishavKumar 这是一个黑客......如果你没有构造函数,只需创建一个构造函数并粘贴上面的代码。实际上,这段代码添加了一个监听器,每次组件获得焦点时它都会重新渲染视图。
【解决方案5】:

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

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

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

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

【讨论】:

  • 可能当你写这个答案时 reactn 不存在。帮自己一个忙:放弃 redux(永远)并切换到 reactn
  • @LucaFagioli 自从我写 RN 以来已经有好几年了。您能否根据这项新技术更新此答案?如果我有上下文,我会这样做
  • 我指的不是这个具体的问题,而是关于 redux 的热情基调,应该说它是软件历史上最复杂的方法之一(来源:25 年的软件开发) .正如您从下面的答案中看到的那样,其他人已经找到了解决同样问题的 2-3 行解决方案。
【解决方案6】:

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

【讨论】:

    【解决方案7】:

    我认为我们有一个非常简单的方法(2021 年有效)。不要使用goBacknavigate,而应使用push

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

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

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

    【讨论】:

    • 另请注意,push 仅适用于 stackNavigators
    【解决方案8】:

    更新 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】:

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

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

      【讨论】:

      • 在这里尝试了几乎所有答案后,这对我有用
      【解决方案10】:

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

      componentDidMount() {
      
          this.init();
      
          this.didFocusSubscription = this.props.navigation.addListener(
            'focus',
            () => {
              this.init();
            }
          );
      
      
        }
      
      
      init = async () => {
         //fetch some data and set state here
         
        }
      

      【讨论】:

        【解决方案11】:

        简单!在useFocusEffect(func)中插入函数

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

        【讨论】:

        • 也适用于 5.x
        【解决方案12】:

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

        首先,我想问一下您使用的是ComponentPureComponent 还是Functional Component。根据您的构造函数注释,听起来您正在扩展一个 Component 类。

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

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

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

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

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

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

        【讨论】:

          【解决方案13】:

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

          【讨论】:

          • TypeError: 无法读取已定义的属性“setOnNavigatorEvent”。
          【解决方案14】:

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

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

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

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

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

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

          所以当注册为“Add Salesman”的新画面将被调用时,一个名为“doChange”的参数也将被转移到其他画面。 现在,在其他屏幕的任何地方调用此方法,通过:

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

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

          【讨论】:

            【解决方案15】:
             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
                        }); 
                }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2019-01-21
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多