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

时间:2017-05-28 04:07:25

标签: react-native

我有一个页面,如果他/她已登录,则会呈现用户的姓名,或者"创建帐户"或者"登录"如果他/她没有选择。屏幕如下

enter image description here

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

enter image description here

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

我怎样才能做到这一点?

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

12 个答案:

答案 0 :(得分:50)

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

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

定义你的回调函数:

refresh() {
  this.doSomething();
}

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

await AsyncStorage.setItem('id_token', myId);
this.props.navigation.state.params.onGoBack();
this.props.navigation.goBack();

答案 1 :(得分:20)

  

有没有办法从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>
    );
  }
}

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

debrice致敬 - 请参阅https://github.com/react-navigation/react-navigation/issues/288#issuecomment-315684617

答案 2 :(得分:11)

我遇到了类似的问题,所以这就是我如何通过更多细节来解决它。

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

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

并导航到孩子:

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

现在在孩子身上可以叫它:

 this.props.navigation.state.params.updateData(status);
 this.props.navigation.goBack();

选项二。为了从任何组件获取数据,正如另一个答案所解释的那样,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));

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

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

有关详细信息,请参阅AsyncStorage docs

答案 3 :(得分:7)

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

  

注意*(这不仅适用于goBack,还会在您每次   输入此页面。)

import { NavigationEvents } from 'react-navigation';

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

答案 4 :(得分:2)

已编辑: 最好的解决方案是使用NavigationEvents,您无需手动创建监听器:)

不强烈建议调用回调函数,请使用侦听器检查此示例(请记住,使用此选项从componentWillUnMount中删除所有侦听器)

组件A

navigateToComponentB() {
  const { navigation } = this.props
  this.navigationListener = navigation.addListener('willFocus', payload => {
    this.navigationListener.remove()
    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
  })
}

组件B

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

有关上一示例的更多详细信息:https://github.com/react-navigation/react-navigation/issues/288#issuecomment-378412411

关于Nicholls

答案 5 :(得分:1)

我只是使用了标准的导航功能,即提供了ViewA路由名称并传递了参数,正是goBack会做的。

this.props.navigation.navigate("ViewA", 
{
     param1: value1, 
     param2: value2
});

答案 6 :(得分:1)

这个解决方案为我做了,根据导航网站:https://reactnavigation.org/docs/function-after-focusing-screen/#re-rendering-screen-with-the-useisfocused-hook

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

useFocusEffect(
    React.useCallback(() => { 
        // YOUR CODE WHEN IT IS FOCUSED
       return // YOUR CODE WHEN IT'S UNFOCUSED
    }, [userId])
);

答案 7 :(得分:0)

如果您使用的是redus,则可以创建一个操作来存储数据并检查父项Component中的值,也可以使用AsyncStorage

但是我认为最好只传递JSON-serializable参数,因为如果有一天您想保存导航状态,那不是很容易。

还请注意react-navigation在实验中具有此功能 https://reactnavigation.org/docs/en/state-persistence.html

  

每个参数,路线和导航状态必须完整   JSON可序列化,此功能才能正常工作。这意味着您   路由和参数不得包含任何函数,类实例或   递归数据结构。

我喜欢在开发模式中使用此功能,当我将参数作为函数传递时,我简直无法使用

答案 8 :(得分:0)

第一个屏幕

updateData=(data)=>{
    console.log('Selected data',data)
}   

this.props.navigation.navigate('FirstScreen',{updateData:this.updateData.bind(this)})

第二屏

// use this method to call FirstScreen method 
execBack(param) {
    this.props.navigation.state.params.updateData(param);
    this.props.navigation.goBack();
}

答案 9 :(得分:0)

我还将使用navigation.navigate。如果有人遇到相同的问题,并且还使用了嵌套导航器,则它的工作方式如下:

onPress={() =>
        navigation.navigate('MyStackScreen', {
          // Passing params to NESTED navigator screen:
          screen: 'goToScreenA',
          params: { Data: data.item },
        })
      }

答案 10 :(得分:0)

在React Navigation v5中,只需使用navigation方法。来自docs

要实现此目的,您可以使用导航方法,其作用类似于 如果屏幕已经存在,请返回。您可以通过传递参数 导航以将数据传回

完整示例:

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',
  },
});

答案 11 :(得分:0)

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

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

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

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

查看下面的代码或访问:Here

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;