React Native:Reach-Navigation和Pouch-DB-在运行“刷新”回调之前未完成db.put

时间:2018-11-23 23:41:03

标签: node.js react-native promise react-navigation pouchdb

相对的新手;如果我的礼节和形式不好,请原谅我。我愿意接受反馈。

我已经使用create-react-native-app创建了一个使用PouchDB(我相信最终会使用AsyncStorage)存储基本项目的应用程序。

在TabNavigator(主应用程序)中,我具有用于应用程序相关部分的StackNavigator(“列表屏幕”)。它查找数据库并查询项目,然后在每个返回的记录上使用.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的组件都包含带有“编辑”选项的react-native-slideout。这些内容的onPress会将用户发送到“项目详细信息”屏幕,并将从PouchDB中选择的项目的_id作为道具传递到“项目详细信息”屏幕,其中loadItem()componentDidMount中运行并执行数据库模块中的db.get(id)。其他细节从该_id(数组中的对象)的“事件”属性列表中显示,该id呈现出另一堆类似ListItem的组件。

当选择“将事件添加到项目列表...”或“将其删除(使用这些项目通过[another]滑出的另一个功能”)出现问题时,会出现类似的向后导航。在“添加事件”屏幕中调用这两个函数中的任何一个之后,形式与上述相同,这是“添加”示例:

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()(用于打印对数据库调用的响应)直到之后一些其他动态记录才记录渲染方法在“项目详细信息”屏幕上被调用。因此,似乎先前的屏幕正在执行get()loadItem()中的Promise链正在解析的createEvent()之前调用的onGoBack()。对于我来说,更大的问题是否是由于状态管理造成的,目前尚不清楚,尽管这在某些方面是有道理的,因为无论我是否调用了{{1}}函数,这种情况都可能发生。

编辑/更改:我试图在db.get()上的db_ops模块和调用它的组件端loadItem()中的各个位置使用异步/等待。在这些时间安排中,有些事情并没有发生变化,我完全被困在这里。除了尝试使用redux(在这种情况下我认为这太过分了)之外,还有什么想法吗?

1 个答案:

答案 0 :(得分:0)

与PDB或导航无关,它与如何管理依赖项中的外部更改有关(因为这些更改已存在于Navigator中,这很重要-要理解很重要-因此componentDidMount不够)。如果您不使用类似全局状态的Redux一样的管理(就像我一样),让依赖组件知道应该更新的唯一方法就是传递相应的prop并检查它们是否被更改。 像这样:

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