Reagiere auf die Navigation goBack () und aktualisiere den übergeordneten Status


73

Ich habe eine Seite, auf der der Name des Benutzers angezeigt wird, wenn er angemeldet ist, oder die Option "Konto erstellen" oder "Anmelden", wenn er nicht angemeldet ist. Bildschirm wie unten

Geben Sie hier die Bildbeschreibung ein

Sie können zur Seite "Anmelden" oder "Konto erstellen" navigieren. Nach erfolgreicher Anmeldung oder Registrierung navigiert es zu dieser Seite und zeigt den Benutzernamen an. Bildschirm wie unten

Geben Sie hier die Bildbeschreibung ein

Derzeit speichere ich Benutzerdaten in AsyncStorage. Ich möchte dieses Feld aktualisieren, sobald sich der Benutzer erfolgreich angemeldet oder registriert hat, wenn er von der Seite umleitet.

Wie kann ich das erreichen?

Gibt es eine Möglichkeit, Parameter von zu übergeben, navigate.goBack()und Eltern können die Parameter abhören und ihren Status aktualisieren?

Antworten:


105

Sie können eine Rückruffunktion als Parameter übergeben, wenn Sie die Navigation wie folgt aufrufen:

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

Und definieren Sie Ihre Rückruffunktion:

refresh() {
  this.doSomething();
}

Dann können Sie in der Anmelde- / Registrierungsansicht vor goBack Folgendes tun:

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

Update für React Navigation v5:

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

1
Hallo, wenn ich es benutze static navigationOptions = ({navigation}) => ({ headerRight: <Button title="test" onPress={() => navigation.navigate('GoToScreen', {onGoBack: () => this.refresh()})} /> });, ärgert es mich, dass es keine gibt this.refresh(). Irgendwelche Lösungen?
Khalil Khalaf

2
Sie können auch onGoBack: this.refresh anstelle vononGoBack: () => this.refresh()
Chicken Suop

1
Verwenden Sie für React Navigation 5.0 this.props.route.params.onGoBack ()
The1993

11
In Version 5 erhalten Sie die Meldung "Im Navigationsstatus wurden nicht serialisierbare Werte gefunden, die die Verwendung unterbrechen können, z. B. das Beibehalten und Wiederherstellen des Status, wenn Sie nur eine Rückruffunktion übergeben.
Toma Radu-Petrescu

1
Die offizielle Option besteht darin, ".navigate" anstelle von ".goBack" zur Ansicht zurückzukehren und einen Parameter zu übergeben. Da der Routenname identisch ist, wird die aktuelle Route entfernt, anstatt eine neue hinzuzufügen. Wenn das übergeordnete Element eine Funktionskomponente ist, können Sie dies tun useEffect(refresh, [route.params?.updateTime])und im untergeordneten Element .navigate("parent", {updateTime: new Date().getTime()}).
user2259659

56

Gibt es eine Möglichkeit, Parameter von zu übergeben, navigate.goback()und Eltern können die Parameter abhören und ihren Status aktualisieren?

Sie können eine Rückruffunktion als Parameter übergeben (wie in anderen Antworten erwähnt).

Hier ist ein klareres Beispiel : Wenn Sie von A nach B navigieren und möchten, dass B Informationen an A zurückgibt, können Sie einen Rückruf übergeben (hier 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} />;
  }
}

Hut ab für Debrice - Siehe https://github.com/react-navigation/react-navigation/issues/288#issuecomment-315684617


Bearbeiten

Für React Navigation v5

ViewB.js

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

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

  render() {
    return <Button title="back" onPress={this.goBack} />;
  }
}

1
Dies war sehr hilfreich für einen Fall, den ich heute hatte, als ich nicht gespeicherte Elemente auf einer Seite nachverfolgen musste. Hat perfekt funktioniert.
IronWorkshop

1
Hallo! Ich könnte zu spät kommen, aber ich bekomme einen Fehler namens undefined is not an object (evaluating navigation.state.params.onSelect)ist keine Funktion,
Min UD

Vielen Dank, dass Sie die Lösung von Debrice geteilt haben. Es funktioniert perfekt wie erwartet (:
TommyLeong

@ MinUD bitte benutzenthis.props.route.params.onSelect
Ali Akram

21

Versuchen Sie dies für diejenigen, die nicht über Requisiten verwalten möchten. Es wird jedes Mal aufgerufen, wenn diese Seite angezeigt wird.

Hinweis * (Dies gilt nicht nur für goBack, sondern wird bei jedem Aufrufen dieser Seite aufgerufen.)

import { NavigationEvents } from 'react-navigation';

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

1
seltsame, aber beste Lösung überhaupt. Es hilft, wenn wir uns jederzeit aktualisieren möchten.
Sunil Zalavadiya

1
Dies ist die beste Antwort, einfach und sehr effektiv. Ich musste jedes Mal einen Bildschirm aktualisieren, wenn ich darauf zurückkam, entweder mit einer Navigation oder einem Zurückdrücken, und dies löst es ohne Komplikationen.
Danilo

19

Ich hatte ein ähnliches Problem. Deshalb habe ich es hier gelöst, indem ich näher auf Details eingegangen bin.

Option 1 besteht darin, mit Parametern zurück zum übergeordneten Element zu navigieren. Definieren Sie einfach eine Rückruffunktion wie folgt in der übergeordneten Komponente :

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

und navigiere zum Kind:

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

Jetzt im Kind kann es genannt werden:

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

Option zwei. Um Daten von einer Komponente abzurufen, kann AsyncStorage, wie in der anderen Antwort erläutert, entweder synchron verwendet werden oder nicht.

Sobald die Daten gespeichert sind, können sie überall verwendet werden.

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

oder verwenden Sie entweder eine asynchrone Funktion, um sie selbst zu aktualisieren, wenn sie auf diese Weise einen neuen Wert erhält.

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

Weitere Informationen finden Sie in den AsyncStorage-Dokumenten .


Der erste Ansatz hat bei mir funktioniert. Mein Ziel war es, einige Daten zu referenzieren, wenn ein Kind auftaucht.
Spydy

@ David In meinem Fall habe ich headerMode als Bildschirm angegeben. Damit die Schaltfläche "Zurück" links automatisch bereitgestellt wird. Ich möchte das Symbol nicht ändern. Aber ich möchte nach goBack () eine Funktion auf den vorherigen Bildschirm ausführen. Bitte sagen Sie mir, wie es geht mach das?
Johncy

1
Siehe auch dieses Beispiel mit dem gleichen Ansatz wie Option 1 github.com/react-navigation/react-navigation/issues/…
Gianfranco P.

Option 1 wie schnelles Schließen. Es ist Arbeit genau, danke Bruder
Chris Nguyen

Ich habe eine Warnmeldung erhalten, Typ "[Ablehnung eines nicht behandelten Versprechens: TypeError: undefined ist kein Objekt (Auswertung von '_this.props.navigation.state.params')]"
Jansha Mohammed

8

BEARBEITET: Die beste Lösung ist die Verwendung von NavigationEvents . Sie müssen keine Listener manuell erstellen :)

Das Aufrufen einer Rückruffunktion wird nicht dringend empfohlen. Überprüfen Sie dieses Beispiel mit einem Listener (Denken Sie daran, alle Listener mit dieser Option aus componentWillUnMount zu entfernen.)

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

Komponente B.

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

Weitere Informationen zum vorherigen Beispiel: https://github.com/react-navigation/react-navigation/issues/288#issuecomment-378412411

Grüße, Nicholls


1
Hat wunderbar
funktioniert

3

Ich habe gerade die Standardnavigationsfunktion verwendet, die den Namen der ViewA-Route angibt und die Parameter übergibt. Ich habe genau das getan, was goBack getan hätte.

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

5
Dies ist NICHT dasselbe wie goBack(). Dies geht weiter zur vorherigen Ansicht (es wird dem Stapel hinzugefügt). Und außerdem glaube ich nicht, dass dies die Frage beantwortet.
Chicken Suop

Ich denke schon - die Frage ist "wie man mit Params zurückgeht". Das ist unabhängig von Ihrem Kommentar zum Zurückgehen oder Vorwärtsgehen. In beiden Fällen können die Parameter vom "Zurück" -Bildschirm übergeben und empfangen werden.
Morgan_il

2
@ElliotSchep Wenn die Route bereits auf dem Stapel ist, Berufung this.props.navigation.navigate ist der gleiche wie der Aufruf goBack(). Probieren Sie es aus, Sie werden sehen. Die Bildschirmanimation wird von links nach rechts verschoben.
Bataleon

1
@ Bataleon Ich war mir dessen nicht bewusst. Sorry morgan_il
Chicken Suop

2
@ElliotSchep Kein Problem, es ist ein bisschen verwirrend und nicht das, was ich als "erwartetes" Verhalten bezeichnen würde. Ich nahm auch an, dass navigation.navigateimmer eine Route auf den Stapel geschoben wurde.
Bataleon

0

Wenn Sie verwenden redus, können Sie eine Aktion zum Speichern von Daten und Überprüfen des Werts im übergeordneten Element erstellen Componentoder verwendenAsyncStorage .

Aber ich denke, es ist besser, nur JSON-serializableParameter zu übergeben, denn wenn Sie eines Tages den Navigationsstatus speichern möchten, ist dies nicht sehr einfach.

Beachten Sie react-navigationauch, dass diese Funktion in experimentellem https://reactnavigation.org/docs/en/state-persistence.html enthalten ist

Jeder Parameter, jede Route und jeder Navigationsstatus muss vollständig JSON-serialisierbar sein, damit diese Funktion funktioniert. Dies bedeutet, dass Ihre Routen und Parameter keine Funktionen, Klasseninstanzen oder rekursiven Datenstrukturen enthalten dürfen.

Ich mag diese Funktion im Entwicklungsmodus und wenn ich Parameter als Funktion übergebe, kann ich sie einfach nicht verwenden


0

Erster Bildschirm

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

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

Zweiter Bildschirm

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

0

Ich würde auch navigation.navigate verwenden. Wenn jemand das gleiche Problem hat und auch verschachtelte Navigatoren verwendet , würde dies folgendermaßen funktionieren:

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

0

Verwenden Sie in React Navigation v5 einfach die Navigationsmethode. Aus den Dokumenten :

Um dies zu erreichen, können Sie die Navigationsmethode verwenden, die sich wie goBack verhält, wenn der Bildschirm bereits vorhanden ist. Sie können die Parameter mit navigieren übergeben, um die Daten zurückzugeben

Vollständiges Beispiel:

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',
  },
});
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.