相对的新手;如果我的礼节和形式不好,请原谅我。我愿意接受反馈。
我已经使用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(在这种情况下我认为这太过分了)之外,还有什么想法吗?
答案 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
}