反应导航goback()并更新父状态

Dar*_*Lau 40 react-native

我有一个页面,如果他/她登录将呈现用户的名字,如果他/她没有,则会创建"创建帐户"或"登录"选项.屏幕如下

在此输入图像描述

他们可以导航到"登录"或"创建帐户"页面.成功登录或注册后,它将导航到此页面,并显示用户名.屏幕如下

在此输入图像描述

目前,我存储用户数据AsyncStorage,我想在用户成功登录后更新此字段,或者在从页面重定向时注册.

我怎样才能做到这一点?

有没有办法传递param navigate.goBack(),父母可以听取参数并更新其状态?

Zha*_*uzz 71

当您像这样调用导航时,可以将回调函数作为参数传递:

  const DEMO_TOKEN = await AsyncStorage.getItem('id_token');
  if (DEMO_TOKEN === null) {
    this.props.navigation.navigate('Login', {
      onGoBack: () => this.refresh(),
    });
    return -3;
  } else {
    this.doSomething();
  }
Run Code Online (Sandbox Code Playgroud)

并定义你的回调函数:

refresh() {
  this.doSomething();
}
Run Code Online (Sandbox Code Playgroud)

然后在登录/注册视图中,在goBack之前,您可以这样做:

await AsyncStorage.setItem('id_token', myId);
this.props.navigation.state.params.onGoBack();
this.props.navigation.goBack();
Run Code Online (Sandbox Code Playgroud)

  • 在 v5 中,您将得到“我们在导航状态中发现了不可序列化的值,如果您只传递回调函数,这可能会破坏持久化和恢复状态等用法。 (29认同)
  • 官方的选项是“.navigate”返回视图而不是“.goBack”,并传入一个参数。由于路由名称相同,因此它将弹出当前路由而不是添加新路由。如果父组件是函数组件,您可以执行 ```useEffect(refresh, [route.params?.updateTime])``` 并在子组件中执行 ```.navigate("parent", {u​​pdateTime: new Date( ).getTime()})```。 (5认同)
  • 你也可以使用`onGoBack:this.refresh`而不是`onGoBack :()=> this.refresh()` (2认同)
  • 对于 React Navigation 5.0,请使用 this.props.route.params.onGoBack() (2认同)

gih*_*uka 33

有没有办法传递param navigate.goback(),父母可以听取参数并更新其状态?

您可以将回调函数作为参数传递(如其他答案中所述).

这是一个更清晰的示例,当您从A导航到B并且您希望B将信息传递回A时,您可以传递回调(此处onSelect):

ViewA.js

import React from "react";
import { Button, Text, View } from "react-native";

class ViewA extends React.Component {
  state = { selected: false };

  onSelect = data => {
    this.setState(data);
  };

  onPress = () => {
    this.props.navigate("ViewB", { onSelect: this.onSelect });
  };

  render() {
    return (
      <View>
        <Text>{this.state.selected ? "Selected" : "Not Selected"}</Text>
        <Button title="Next" onPress={this.onPress} />
      </View>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

ViewB.js

import React from "react";
import { Button } from "react-native";

class ViewB extends React.Component {
  goBack() {
    const { navigation } = this.props;
    navigation.goBack();
    navigation.state.params.onSelect({ selected: true });
  }

  render() {
    return <Button title="back" onPress={this.goBack} />;
  }
}
Run Code Online (Sandbox Code Playgroud)

debrice做好准备 - 请参阅https://github.com/react-navigation/react-navigation/issues/288#issuecomment-315684617

  • 嘿!我可能会迟到,但我收到一个错误,名为``undefine is not an object (evaluating navigation.state.params.onSelect)``is not a function, (2认同)

Ner*_*Jok 13

我遇到了类似的问题,所以这里是我通过更多细节来解决它的方法.

选项一是使用参数导航回父级,只需在父组件中定义一个回调函数:

updateData = data => {
  console.log(data);
  alert("come back status: " + data);
  // some other stuff
};
Run Code Online (Sandbox Code Playgroud)

并导航到孩子:

onPress = () => {
  this.props.navigation.navigate("ParentScreen", {
    name: "from parent",
    updateData: this.updateData
  });
};
Run Code Online (Sandbox Code Playgroud)

现在在孩子身上可以叫:

 this.props.navigation.state.params.updateData(status);
 this.props.navigation.goBack();
Run Code Online (Sandbox Code Playgroud)

方案二.为了从任何组件获取数据,正如另一个答案所解释的那样,AsyncStorage可以同步使用,也可以不同步使用.

保存数据后,可以在任何地方使用.

// to get
AsyncStorage.getItem("@item")
  .then(item => {
    item = JSON.parse(item);
    this.setState({ mystate: item });
  })
  .done();
// to set
AsyncStorage.setItem("@item", JSON.stringify(someData));
Run Code Online (Sandbox Code Playgroud)

或者使用异步函数使其在获得新值时自动更新.

this.state = { item: this.dataUpdate() };
async function dataUpdate() {
  try {
    let item = await AsyncStorage.getItem("@item");
    return item;
  } catch (e) {
    console.log(e.message);
  }
}
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请参阅AsyncStorage文档.


Sag*_*ada 11

对于那些不想通过道具进行管理的人,请尝试此操作。此页面出现时,它将每次调用。

注意*(这不仅适用于goBack,而且每次您进入此页面时都会调用。)

import { NavigationEvents } from 'react-navigation';

    render() {
            return (
              <View style={{ flex: 1 }}>
                <NavigationEvents
                  onWillFocus={() => {
                    // Do your things here
                  }}
                />
              </View>
            );
          }
Run Code Online (Sandbox Code Playgroud)


sau*_*ito 11

使用React Navigation v5,只需使用navigate 方法。来自文档

为此,您可以使用导航方法,如果屏幕已存在,该方法的作用类似于 goBack。您可以通过导航传递参数以将数据传回

完整示例:

import React from 'react';
import { StyleSheet, Button, Text, View } from 'react-native';

import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';

const Stack = createStackNavigator();

function ScreenA ({ navigation, route }) {
  const { params } = route;

  return (
    <View style={styles.container}>
      <Text>Params: {JSON.stringify(params)}</Text>
      <Button title='Go to B' onPress={() => navigation.navigate('B')} />
    </View>
  );
}

function ScreenB ({ navigation }) {
  return (
    <View style={styles.container}>
      <Button title='Go to A'
        onPress={() => {
          navigation.navigate('A', { data: 'Something' })
        }}
      />
    </View>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator mode="modal">
        <Stack.Screen name="A" component={ScreenA} />
        <Stack.Screen name="B" component={ScreenB} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});
Run Code Online (Sandbox Code Playgroud)

  • 这是正确的(最新的)答案 - 想知道为什么它如此之低。 (2认同)
  • 这会弄乱堆栈历史记录。goBack 从历史堆栈中删除当前屏幕,而“navigation.navigate”只是将新屏幕推送到堆栈上。 (2认同)

jdn*_*lsc 10

最好的解决方案是使用NavigationEvents。您不需要手动创建侦听器。

Calling a callback function is not highly recommended. Check this example using a listener (Remember to remove all listeners from componentWillUnMount with this option).

Component A:

navigateToComponentB() {
  const { navigation } = this.props
  this.navigationListener = navigation.addListener('willFocus', payload => {
    this.removeNavigationListener()
    const { state } = payload
    const { params } = state
    //update state with the new params
    const { otherParam } = params
    this.setState({ otherParam })
  })
  navigation.push('ComponentB', {
    returnToRoute: navigation.state,
    otherParam: this.state.otherParam
  })
}
removeNavigationListener() {
  if (this.navigationListener) {
    this.navigationListener.remove()
    this.navigationListener = null
  }
}
componentWillUnmount() {
  this.removeNavigationListener()
}
Run Code Online (Sandbox Code Playgroud)

Commponent B:

returnToComponentA() {
  const { navigation } = this.props
  const { routeName, key } = navigation.getParam('returnToRoute')
  navigation.navigate({ routeName, key, params: { otherParam: 123 } })
}
Run Code Online (Sandbox Code Playgroud)

For more details of the previous example: https://github.com/react-navigation/react-navigation/issues/288#issuecomment-378412411


小智 8

渲染所需组件的最简单方法是使用useIsFocused挂钩。

React Navigation 提供了一个钩子,它返回一个布尔值,指示屏幕是否获得焦点。当屏幕聚焦时,钩子将返回 true;当我们的组件不再聚焦时,钩子将返回 false。

首先将其导入到您想要返回的所需页面中。 import { useIsFocused } from '@react-navigation/native';

然后,将其存储在任何变量中,并使用 React useEffect 钩子渲染组件更改。

请参阅下面的代码或访问:此处

import React, { useState } from 'react';
import { useIsFocused } from '@react-navigation/core';

const HomeScreen = () => {
  const isFocused = useIsFocused();
  
  useEffect(()=>{
        console.log("Focused: ", isFocused); //called whenever isFocused changes
    }, [isFocused]);
    
    return (
      <View>
        <Text> This is home screen! </Text>
      </View>
    )
}

export default HomeScreen;
Run Code Online (Sandbox Code Playgroud)