Обновить предыдущий экран в goBack()

Я новичок в React Native. Как мы можем обновить/перезагрузить предыдущий экран, вернувшись к нему, вызывая goBack()?

Допустим, у нас есть 3 экрана A, B, C:

A -> B -> C

Когда мы запускаем goBack() с экрана C, он возвращается на экран B, но со старым состоянием/данными. Как мы можем его обновить? Конструктор не называется 2-й раз.

Ответ 1

Да, конструктор вызывается только в первый раз, и вы не можете назвать его дважды.

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

Лучше: вы можете вернуться в свою первую сцену, которая также обновляет сцену, возвращаясь назад и передавая назад функцию вниз. Таким образом, вторая сцена не будет знать о вашей функции обновления, которая является разумной.

Лучшее: вы можете использовать сокращение и отправить действие назад во второй сцене. Затем в вашем редукторе вы позаботитесь о возврате и освежении своей сцены.

Ответ 2

Добавление Api Call в callBack решает проблему

componentDidMount() {
    this.props.fetchData();
    this.willFocusSubscription = this.props.navigation.addListener(
      'willFocus',
      () => {
        this.props.fetchData();
      }
    );
  }

  componentWillUnmount() {
    this.willFocusSubscription.remove();
  }

Ответ 3

Встроенная функция слушателя, которая поставляется с React-Navigation, будет самым простым решением. Всякий раз, когда компонент снова "фокусируется" на элементе навигации, слушатель срабатывает. Написав функцию loadData, которую можно вызывать как при загрузке компонента, так и при получении уведомления от слушателя, вы можете легко перезагрузить данные при переходе назад.

   componentWillMount(){
    this._subscribe = this.props.navigation.addListener('didFocus', () => {
     this.LoadData();
     //Put your Data loading function here instead of my this.LoadData()
    });}

Ответ 4

На вашем экране B конструктор будет работать как по волшебству :)

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

Ответ 5

Если вы пытаетесь получить новые данные в предыдущем представлении, и он не работает, вы можете вернуться к тому, чтобы начать с того, как вы отправляете данные в эту точку зрения. Вызов goBack не должен влиять на установку предыдущего компонента и, скорее всего, не вызовет его конструктор, как вы уже отметили.

В качестве первого шага я бы спросил, используете ли вы компонент, компонент PureComponent или функциональный компонент. На основе вашего комментария конструктора звучит так, будто вы расширяете класс Component.

Если вы используете компонент, метод рендеринга подчиняется shouldComponentUpdate, и значение вашего состояния находится под вашим контролем.

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

Если вы используете конструктор для вызова какой-либо функции API или async, подумайте о том, чтобы переместить эту функцию в родительский компонент как маршрута, который вы вызываете goBack и компонента, который вы хотите обновить, с помощью последних данных, Затем вы можете попросить своего родительского компонента повторно запросить API или обновить его состояние из дочернего компонента.

Если Route C обновляет "состояние/данные" приложения, это обновление должно распространяться на общего родителя маршрутов A, B и C, а затем передаваться в качестве опоры.

В качестве альтернативы вы можете использовать решение управления состоянием, такое как Redux, чтобы поддерживать это состояние независимо от родительских/дочерних компонентов - вы должны были бы обернуть ваши компоненты в компонент более высокого уровня connect, чтобы получать последние обновления в любое время, когда изменяется состояние приложения.

TL; DR В конечном итоге это звучит так, как будто ответ на ваш вопрос основан на том, где хранится ваше состояние приложения. Он должен храниться достаточно высоко в вашей иерархии компонентов, чтобы каждый маршрут всегда получал последние данные в качестве опоры, переданные от своего родителя.

Ответ 6

В этом ответе предполагается, что используется библиотека реагирования-натуральной навигации, что маловероятно, потому что на самом деле у нее нет метода goBack()...

Конструктор не вызывает второй раз, потому что экран A и B все еще отображаются (но скрыты за экраном C). Если вам нужно знать, когда экран B снова будет виден, вы можете прослушивать события навигации.

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

Другие события: willDisappear, didAppear, didDisappear

Альтернативное решение вашей проблемы заключается в использовании решения управления состоянием, такого как Redux, для предоставления состояния всем экранам всякий раз, когда он обновляется (а не только на переходах на экране). См. Пример old response-native-nav/redux.

Ответ 7

Ни один из этих ответов не сработал для меня, к сожалению, но я нашел простую библиотеку, она выполняет ту же работу:

npm install --save react-native-event-listeners

componentDidMount() {
        this.listener = EventRegister.addEventListener('reloadData', (data) => {
            console.log("data is fetched");
            this.updateState(data); // private function that update the state using setState to trigger render
        });
    }

componentWillUnmount() {
    EventRegister.removeEventListener(this.listener)
}

И в другом компоненте, в моем случае кнопка непрозрачности:

<TouchableOpacity
            onPress={() => {
                fetch('url').then(data => {
                    ServiceLocator.saveData('matba', data);
                    EventRegister.emit('reloadData', data);
                    props.nav.goBack()
                })
                    .catch(error =>{
                        console.log(error);
                        Alert.alert("Cannot connect to the server");
                        props.nav.goBack()
                    });
            }}
        >