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

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

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

A -> B -> C

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


comment
У вас есть решение этого? Подскажите пожалуйста, я тоже с этим столкнулся. Я решил это.   -  person Deepak Sachdeva    schedule 10.11.2017
comment
Да, @DeepakSachdeva спасибо, но вы можете поделиться своими выводами для получения знаний. Следующее помогло мне stackoverflow.com/a/46892405/2086124   -  person Adnan Ali    schedule 17.11.2017
comment
Интересно, как вы конкретно решаете эту проблему, так как у меня такая же проблема. Вы ссылаетесь на ответ ниже, но какой из трех вариантов представил пользователь @Bat? Также было бы намного лучше, если бы вы ответили на свой вопрос подробно о том, как вы его решаете. Так как это действительно поможет тем, у кого в будущем возникнет та же проблема, что и у вас. Надеюсь, вы сможете это опубликовать. Бог благословил.   -  person Edper    schedule 20.01.2018


Ответы (14)


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

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

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

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

person Bat    schedule 23.10.2017
comment
Вероятно, когда вы написали этот ответ, реакции не было. Сделайте себе одолжение, ребята: откажитесь от redux (навсегда) и переключитесь на reactn. - person Luca Fagioli; 11.01.2021
comment
@LucaFagioli Прошло много лет с тех пор, как я писал RN. Не могли бы вы обновить этот ответ в соответствии с этой новой технологией? Я бы сделал это, если бы у меня был контекст - person Bat; 17.01.2021
comment
Я имел в виду не этот конкретный вопрос, а восторженный тон по поводу редукции, который следует упомянуть как один из самых сложных подходов в истории программного обеспечения (источник: 25 лет разработки программного обеспечения). Как вы можете видеть из ответов ниже, кто-то уже нашел решение из 2-3 строк для решения той же проблемы. - person Luca Fagioli; 17.01.2021

Добавление вызова API в callBack фокуса на экране, на который вы возвращаетесь, решает проблему.

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

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

ОБНОВЛЕНИЕ 2021:

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

  componentWillUnmount() {
    this.willFocusSubscription();
  }

Если вы используете React Hook:

  React.useEffect(() => {
      fetchData();
      const willFocusSubscription = props.navigation.addListener('focus', () => {
        fetchData();
    });

    return willFocusSubscription;
}, []);
person Mukundhan    schedule 22.06.2018
comment
Это должен быть ответ. Работает отлично, если поместить в правильный экран (экран будет отображаться при нажатии кнопки «Назад»). Также включает неустаревшие методы. Ницца! :) - person Imdad; 25.03.2019
comment
Пока мы работали над проектом, получение данных было ключевым моментом при нажатии кнопки «Назад». Хорошо, что вовремя решилась :) - person Mukundhan; 02.04.2019
comment
Mukundhan, будет ли willFocus автоматически запускаться после goBack()? Также все данные повторной выборки попадают в fetchData()? - person user938363; 17.07.2019
comment
Да, он будет вызываться при нажатии назад. Только детали, которые могут быть изменены при переходе на новую страницу, могут быть получены в fetchData(). - person Mukundhan; 18.07.2019
comment
Идеально подходит для моих нужд! Большое спасибо. ты спасаешь мой день. - person Code Cooker; 27.01.2020
comment
Да, addListener на объекте navigation с событием willFocus помогло. Благодарю вас! - person HartleySan; 19.05.2020
comment
Пришлось использовать только «фокус», чтобы он вообще работал. 'willFocus' и 'didFocus' не работали - person 3nuc; 24.06.2020
comment
При отказе от подписки мне пришлось this.willFocusSubscription() как указано в документах: reactnavigation.org/docs/navigation-events/ - person Steffi; 23.03.2021

Как насчет использования хука useIsFocused?

https://reactnavigation.org/docs/function-after-focusing-screen/#re-rendering-screen-with-the-useisfocused-hook

const componentB = (props) => { 
  // check if screen is focused
  const isFocused = useIsFocused();

  // listen for isFocused, if useFocused changes 
  // call the function that you use to mount the component.

  useEffect(() => {
    updateSomeFunction()
  },[isFocused]);
}
person Onur Eker    schedule 23.05.2020
comment
На мой взгляд, это идеальное решение...! - person sudonitin; 25.07.2020
comment
Это самый простой способ для начинающих. Я не знаю, почему этот ответ не на вершине. - person rafwell; 07.12.2020
comment
@rafwell Я не новичок, но мне нравится простота ответа. ???? - person leeCoder; 19.01.2021
comment
После стольких усилий проблема решена с помощью вашего решения. Спасибо, приятель. - person Arihant Jain; 22.01.2021
comment
Работает для меня, спасибо. Я только что добавил useEffect(() => {isFocused && updateSomeFunction() },[isFocused]);, чтобы получать данные только тогда, когда он сфокусирован. - person Colo Ghidini; 05.05.2021
comment
Да, это идеальное решение для крючков - person Grant Singleton; 30.06.2021

Для реактивной навигации 5.x используйте

5.x

использовать

componentDidMount() {
  this.loadData();

  this.focusListener = this.props.navigation.addListener('focus', () => {
    this.loadData();
    //Put your Data loading function here instead of my this.loadData()
  });
}

Для функциональной составляющей

function Home({ navigation }) {
  React.useEffect(() => {
    const unsubscribe = navigation.addListener('focus', () => {
      loadData();
      //Put your Data loading function here instead of my loadData()
    });

    return unsubscribe;
  }, [navigation]);

  return <HomeContent />;
}
person kvadityaaz    schedule 27.07.2020
comment
Не могли бы вы привести пример функционального компонента? - person Nathileo; 28.07.2020
comment
Это самое чистое простое решение. - person Yogesch; 04.07.2021

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

    this.props.navigation.addListener(
          'didFocus',
          payload => {
            this.setState({is_updated:true});
          }
    );
person Brijesh Singh    schedule 17.10.2018
comment
привет брат, пожалуйста, не могли бы вы предоставить мне пример кода .. Я также столкнулся с этой проблемой. - person Rishav Kumar; 12.12.2018
comment
@RishavKumar Это хак ... просто создайте конструктор, если у вас его нет, и вставьте приведенный выше код. На самом деле этот код добавляет слушателя, и каждый раз, когда компонент получает фокус, он повторно отображает представления. - person Brijesh Singh; 13.12.2018

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

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

Обновите React-Navigation v5 и используйте React Hooks. На самом деле, использование такое же, как и в базовом классе реакции. Для получения более подробной информации ознакомьтесь с документацией здесь

Вот пример кода:

function Profile({ navigation }) {
  React.useEffect(() => {
    const unsubscribe = navigation.addListener('focus', () => {
      // do something
    });

    return unsubscribe;
  }, [navigation]);

  return <ProfileContent />;
}

Как и в приведенном выше коде, мы добавляем прослушиватель событий при изменении навигации по переменной, затем делаем что-то вроде вызова функции refresh() и, наконец, возвращаем функцию для удаления прослушивателя событий. Простой!

person nahoang    schedule 08.10.2020

Я думаю, у нас есть очень простой способ (работающий в 2021 году) сделать это. Вместо использования goBack или navigate следует использовать push

this.props.navigation.push('your_route_B'). 

Вы также можете передавать параметры так же, как мы передаем в navigate.

Единственная разница ч/б navigate и push в том, что navigate проверяет, существует ли маршрут, который мы проходим, в стеке. Таким образом, мы переходим к более старому, но push просто отправляет нас туда, не проверяя, находится ли он в стеке или нет (т.е. посещался ли маршрут ранее или нет).

person Irfan wani    schedule 24.01.2021
comment
Также обратите внимание, что push доступен только для stackNavigators. - person Irfan wani; 24.01.2021

У меня похожая ситуация, и я обновлялся, чтобы сбросить маршрут при нажатии кнопки «Назад». Итак, что происходит, когда нажимается кнопка «Назад», экран повторно помещается в стек, и useEffect на моем экране загружает данные

navigation.reset({
  index: 0,
  routes: [{ name: "SCREEN WHERE THE GOBACK BUTTON SHOULD GO" }],
});

person ehtulhaq    schedule 29.05.2020
comment
Это сработало для меня после того, как я попробовал почти все ответы здесь - person Nathileo; 28.07.2020

Для реагирования на навигацию (5.x) вам просто нужно добавить подписку на фокус и поместить логику инициализации вашего компонента в отдельную функцию, например так:

componentDidMount() {

    this.init();

    this.didFocusSubscription = this.props.navigation.addListener(
      'focus',
      () => {
        this.init();
      }
    );


  }


init = async () => {
   //fetch some data and set state here
   
  }
person Acheme Paul    schedule 28.01.2021

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

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

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

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

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

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

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

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

person joel.bowen    schedule 30.09.2017

Этот ответ предполагает, что используется библиотека react-native-navigation, что маловероятно, потому что на самом деле у нее нет метода 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, для предоставления состояния всем экранам при каждом их обновлении (а не только при переходах между экранами. См. старый пример react-native-nav/redux.

person Royce Townsend    schedule 01.10.2017
comment
TypeError: Не удается прочитать свойство setOnNavigatorEvent определенного. - person Luvnish Monga; 13.07.2018

Благодаря @Bat. Я потратил много часов на поиск ответа и, наконец, получил базовое решение, которое работает в соответствии с моими потребностями. Хотя я очень волновался. Просто сделайте такую ​​​​функцию в своем предыдущем действии, обязательно привяжите ее.

    changeData(){
    var mydata= salesmanActions.retrieveAllSalesman();
    this.setState({dataListFill: mydata});
    alert('' + mydata.length);
    }

Просто, затем в конструкторе привяжите это,

    this.changeData= this.changeData.bind(this);

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

    onPress={() => this.props.navigation.navigate('Add Salesman', {doChange: 
    this.changeData} )}

Таким образом, когда будет вызван новый экран, зарегистрированный как «Добавить продавца», параметр с именем «doChange», которому назначена функция, также будет передан на другой экран. Теперь на другом экране вызовите этот метод в любом месте:

    this.props.route.params.doChange();

Меня устраивает. Я надеюсь, что это сработает и для вас, СПАСИБО за идею @Bat.

person Mehdi Raza    schedule 25.03.2020

Легко! вставьте функцию внутрь useFocusEffect(func)

import { useFocusEffect } from '@react-navigation/native' 
person Turjoy Saha    schedule 21.06.2021