React navigation goback() и обновить родительское состояние

У меня есть страница, которая будет отображать имя пользователя, если он вошел в систему или "Создать учетную запись" или "Войти", если он/нет. Экран, как показано ниже

enter image description here

Они могут перейти на страницу "Войти" или "Создать учетную запись". После успешного входа в систему или регистрации он перейдет на эту страницу и отобразит имя пользователя. Экран, как показано ниже

enter image description here

В настоящее время я храню данные пользователя в AsyncStorage, я хочу обновить это поле после успешного входа в систему или регистрации при переадресации с этой страницы.

Как я могу это достичь?

есть ли способ передать параметр из navigate.goback() и родитель может прослушивать параметры и обновлять его состояние?

Ответы

Ответ 1

Вы можете передать функцию обратного вызова в качестве параметра, когда вы вызываете навигацию следующим образом:

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

Ответ 2

Есть ли способ передать param из navigate.goback() и родитель может прослушать params и обновить его состояние?

Вы можете передать функцию обратного вызова в качестве параметра (как упоминалось в других ответах).

Вот более ясный пример, когда вы переходите от А к В и хотите, чтобы Б передавал информацию обратно А, вы можете передать обратный вызов (здесь на 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} />;
  }
}

Снимите шляпу для мусора - обратитесь к https://github.com/react-navigation/react-navigation/issues/288#issuecomment-315684617

Ответ 3

Я столкнулся с аналогичной проблемой, так вот как я решил ее, зайдя более подробно.

Первый вариант - вернуться к родительскому с параметрами, просто определите в нем функцию обратного вызова, как это в родительском компоненте:

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

или либо использовать функцию async, чтобы сделать ее самообновлением, когда она получает новое значение, делая так.

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

Дополнительную информацию см. В документах AsyncStorage.

Ответ 4

Для тех, кто не хочет управлять через реквизит, попробуйте это. Он будет звонить каждый раз, когда эта страница появится.

Примечание * (это не только для goBack, оно будет вызываться каждый раз, когда вы заходите на эту страницу.)

import { NavigationEvents } from 'react-navigation';

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

Ответ 5

EDITED: лучшее решение - использовать NavigationEvents, вам не нужно создавать слушателей вручную :)

Вызывать функцию обратного вызова не рекомендуется, проверьте этот пример с помощью слушателя (не забудьте удалить все слушатели из componentWillUnMount с помощью этой опции)

Компонент А

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

Компонент Б

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

С уважением, Николлс

Ответ 6

Я просто использовал стандартную навигационную функцию, указав имя маршрута ViewA и передав параметры, сделал именно то, что сделал бы goBack.

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

Ответ 7

Если вы используете redus вы можете создать действие для хранения данных и проверить значение в родительском Component или вы можете использовать AsyncStorage.

Но я думаю, что лучше передавать только JSON-serializable параметры, потому что если когда-нибудь вы захотите сохранить состояние навигации, это будет не очень легко.

Также обратите внимание, что у react-navigation есть эта функция в экспериментальном https://reactnavigation.org/docs/en/state-persistence.html

Каждый параметр, маршрут и состояние навигации должны быть полностью JSON-сериализуемыми, чтобы эта функция работала. Это означает, что ваши маршруты и параметры не должны содержать функций, экземпляров классов или рекурсивных структур данных.

Мне нравится эта функция в режиме разработки, и когда я передаю params как функцию, я просто не могу ее использовать