React Native: Reach-Navigation и Pouch-DB - db.put не выполнен до запуска обратного вызова «refresh» - PullRequest
0 голосов
/ 24 ноября 2018

Относительный новичок;прости меня, если мой этикет и форма здесь не велики.Я открыт для обратной связи.

Я использовал create-Reaction-native-app для создания приложения, используя PouchDB (который, я считаю, в конечном итоге использует AsyncStorage) для хранения списка «элементов» (в основном).

В TabNavigator (основное приложение) у меня есть StackNavigator («Экран списка») для соответствующей части приложения.Он просматривает БД и запрашивает элементы, а затем I .map () для каждой возвращаемой записи, чтобы динамически генерировать пользовательские компоненты, подобные ListView.Если записей нет, поочередно отображается подсказка, сообщающая об этом пользователю.В любом случае есть TouchableOpacity «Добавить элемент», который выводит их на экран, где они добавляют новый элемент (для которого они выводятся на экран «Добавить»).

При переходе назад отЭкран «Добавить» Я использую шаблон, который довольно часто обсуждается здесь, на SO, в котором я передал функцию «обновить» в качестве параметра навигации.Как только пользователь использует кнопку на экране «Добавить», чтобы «сохранить» изменения, он затем выполняет db.post () и добавляет их элемент, запускает функцию «обновить» в «Экране списка» и затем перемещается назад, какитак:

<TouchableOpacity
           style={styles.myButton}
           onPress={() => {
              if (this.state.itemBrand == '') {
                Alert.alert(
                'Missing Information',
                'Please be sure to select a Brand',
                  [
                    {text: 'OK', onPress: () => 
                    console.log('OK pressed on AddItemScreen')},
                  ],
                { cancelable: false }
                )
              } else {
                this.createItem();
                this.props.navigation.state.params.onGoBack();
                this.props.navigation.navigate('ItemsScreen');
               }
              }
            } 
         >

И все это прекрасно работает.Функция «обновить» (переданная как параметр onGoBack) работает нормально ... для этого экрана.База данных вызывается с запросом, новая запись найдена, и компоненты для элемента отображаются как обаяние.

Каждый из визуализированных компонентов, похожих на ListItem на «экране списка», содержит реагирующий нативный-Slideout с опцией «Редактировать».OnPress для них отправит пользователя на экран «Сведения об элементе», а _id выбранного элемента из PouchDB передается в качестве реквизита на экран «Сведения об элементе», где loadItem() выполняется в componentDidMount и выполняет db.get(id)в модуле базы данных.Дополнительные подробности показаны в списке свойства «events» для этого _id (которые являются объектами в массиве), которые отображаются в другой набор компонентов, подобных ListItem.

Проблема возникает, когда любой из них выбирает "Добавить "событие в список для элемента ... или Удалить его (используя другую функцию с помощью [другого] слайда для этих элементов). Существует аналогичная обратная навигация, вызываемая в той же форме, что и выше, после того, как любая из двух функцийвызывается из экрана «Добавить событие», это пример «Добавить»:

async createEvent() {
    var eventData = {
      eventName: this.state.eventName.trim(),
      eventSponsor: this.state.eventSponsor.trim(),
      eventDate: this.state.eventDate,
      eventJudge: this.state.eventJudge.trim(),
      eventStandings: this.state.eventStandings.trim(),
      eventPointsEarned: parseInt(this.state.eventPointsEarned.trim()),
    };

    var key = this.key;
    var rev = this.rev;
    await db.createEvent(key, rev, eventData);
  }

, который вызывает мою функцию модуля «db_ops»:

exports.createEvent = function (id, rev, eventData) { 
console.log('You called db.createEvent()');
db.get(id)
.then(function(doc) {
    var arrWork = doc.events; //assign array of events to working variable
    console.log('arrWork is first assigned: ' + arrWork);
    arrWork.push(eventData);
    console.log('then, arrWork was pushed and became: ' + arrWork);

    var arrEvents = arrWork.sort((a,b)=>{
        var dateA = new Date(a.eventDate), dateB = new Date(b.eventDate);
         return b.eventDate - a.eventDate;
     })
    doc.events = arrEvents;

    return db.put(doc);
})
.then((response) => {
    console.log("db.createEvent() response was:\n" + 
    JSON.stringify(response));
})
.catch(function(err){
    console.log("Error in db.createEvent():\n" + err);
});
} 

После чего «Добавить событие»«Кнопка экрана запускает вышеупомянутое в последовательности, аналогичной первой, непосредственно перед переходом назад:

this.createEvent();
this.props.navigation.state.params.onGoBack();
this.props.navigation.navigate('ItemsDetails');

Функция« обновления »выглядит так (также вызывается в componentDidMount):

    loadItem() {
      console.log('Someone called loadItem() with this.itemID of ' + this.itemID);
  var id = this.itemID;
  let totalWon = 0;
  db.loadItem(id)
  .then((item) => {
    console.log('[LOAD ITEM] got back data of:\n' + JSON.stringify(item));
    this.setState({objItem: item, events: item.events});

    if (this.state.events.length != 0) { this.setState({itemLoaded: true});
      this.state.events.map(function(event) { 
        totalWon += parseInt(event.eventPointsEarned);
        console.log('totalWon is ' + totalWon + ' with ' +
        event.eventPointsEarned + ' having been added.');
      });
    };
    this.setState({totalWon: totalWon});
  })
  .catch((err) => { 
    console.log('db.loadItem() error: ' + err);
    this.setState({itemLoaded: false});
  });    
 }

Я в недоумении, почему Экран списка обновляется, когда я добавляю элемент ... но не когда я выполняю другие асинхронные операции с БД с PouchDB, что, по моему мнению, аналогично изменениюобъект, содержащий информацию о «событии» и возвращающийся к экрану «Сведения об элементе».

Я где-то облажался с цепочкой Promise?Пренебрегая поведением StackNavigator при более глубокой навигации?

Единственное другое отличие состоит в том, что я манипулирую массивом в функции db в нерабочем случае, тогда как другие я просто создаю / публикую или удаляю / удаляю запись и т. Д. Перед тем, как идтивернуться к состоянию обновления на предыдущем экране.

Редактировать, чтобы добавить, согласно комментариям, возврат к «Экрану списка», и открытие «Сведения об элементе» действительно извлекает данные базы данных и правильно показывает, что обновление было выполнено..

Дальнейшая проверка, которую я сделал, также показала, что console.log в createEvent() для печати ответа на вызов db не регистрируется до после , некоторые другие методы динамического рендеринга вызываютна экране «Сведения об элементе».Таким образом, кажется, что предыдущий экран выполняет get(), который loadItem() вызывает до цепочки Promise в createEvent().Вопрос о том, является ли большая проблема из-за управления состоянием, мне пока неясен - хотя в некоторых отношениях это имело бы смысл - поскольку это могло происходить независимо от того, вызывал ли я свою функцию onGoBack().

Edit / bump: я пытался поместить async / await для использования в различных местах как в модуле db_ops в db.get (), так и в loadItem () на стороне компонента, который его вызывает.Есть что-то такое во времени, что не работает, и я просто застрял здесь.Есть ли у вас какие-нибудь идеи, кроме опробования редукса (что, я думаю, излишне в данном конкретном случае)?

1 Ответ

0 голосов
/ 24 ноября 2018

Нет ничего общего с PDB или навигацией, речь идет о том, как вы управляете внешними изменениями в ваших зависимых (уже смонтированных в Navigator, так как они есть в истории - важно понимать - поэтому componentDidMount не достаточно) компонентах.Если вы не используете глобальное управление избыточными состояниями (как я), единственный способ сообщить зависимому компоненту, который он должен обновить, - передать соответствующие реквизиты и проверить, не были ли они изменены.Вот так:

    //root.js
    refreshEvents = ()=> { //pass it to DeleteView via screenProps
        this.setState({time2refreshEvents: +new Date()}) //pass time2refreshEvents to EventList via screenProps
      }

    //DeleteView.js
    //delete button... 
onPress={db.deleteThing(thingID).then(()=> this.props.screenProps.refreshEvents())}

    //EventList.js
    ...
    constructor(props) {
        super(props);
        this.state = {
          events: [],
          noEvents: false,
          ready: false,
          time2refreshEvents: this.props.screenProps.time2refreshEvents,
          }
      }

    static getDerivedStateFromProps(nextProps, currentState) {
        if (nextProps.screenProps.time2refreshEvents  !== currentState.time2refreshEvents ) {
          return {time2refreshEvents : nextProps.screenProps.time2refreshEvents }
        } else {
          return null
        }
      }

    componentDidMount() {
        this._getEvents()
      }

    componentDidUpdate(prevProps, prevState) {
        if (this.state.time2refreshEvents !== prevState.time2refreshEvents) {
          this._getEvents()
        }
      }

    _getEvents = ()=> {
    //do stuff querying db and updating your list with actual data
    }
...