我正在制作一个简单的反应本机应用程序,它有几个列表,它使用户有机会更新任何列表中的项目或将新项目添加到列表中。
但是,正如之前在StackOverflow上指出的那样,人们无法将项目添加或推送到ListView,因为它应该是一个不可变的数据结构。即在此代码中,无法将新项目推送到数据源
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
var data = ds.cloneWithRows(responseData)
var obj = {};
obj['someproperty'] = 'foo';
data.push(obj); //cannot push a new item into data
所以我所做的就是保留我从服务器获取的数据的副本(下面代码为this.state.items;
)(我称之为cloneWithRows
),附加到该副本(如果它是一个编辑,则更新它),然后在变更(通过编辑或创建新项目)和更新时随时调用变异副本上的cloneWithRows
ui,然后更新服务器(这个反应原生应用程序范围之外的最后一部分)..总而言之,我有一个数据的副本,我可以变异以用作{{1}的数据源当我做出改变时
然而,保留数据结构的缓存似乎没有多大意义,我只能将其作为不可变数据结构(ds.cloneWithRows
的源的唯一目的进行变异。下面的代码)如果我想乐观地更新UI(即在保存在服务器上之前显示更改)。
替代方案(对我来说也没什么意义)似乎是更新服务器,并等待响应(不保留任何类型的缓存)任何时候我更新或添加新项目到我的列表,但这会很慢吗?
问题:如果没有将数据的可变副本保存为缓存,有没有办法在反应原生中乐观地更新ui?
listForUI: ds.cloneWithRows(t)
答案 0 :(得分:1)
不,我非常确定没有任何其他方式来更新ListView数据源,因为正如您所解释的那样,它是不可变的。不变性意味着在添加之前你总是需要复制任何东西。
你提到:
然而,保留数据结构的缓存似乎没有多大意义,我只能将其作为不可变数据结构的源来改变...
我不确定为什么你觉得保留这个缓存没有意义。我也不认为它是导致性能问题的原因,因为缓存仅在addNewItemToList
运行时短暂存在。
答案 1 :(得分:1)
如果要撤消乐观更新,则需要存储以前的项目。要做到这一点,你需要"缓存"或以某种方式存储对先前数据的引用。
您可以乐意在this.setState
处理程序中调用addNewItemToList
并更新您的状态(导致重新呈现),然后在fetch
中,您可以在必要时还原更改(即如果呼叫失败):
addNewItemToList: function(id) {
// Store current list of items and calculate new list
var prevItems = this.state.listForUI.slice();
var newItems = this.state.items.concat([id]);
// Optimistically set new items list; will cause a re-render
this.setState({
listForUI: this.state.listForUI.cloneWithRows(newItems)
});
// Update server with change
fetch('http://localhost:8080/accounts/1/lists/3/todos', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
//code ommitted
})
// Catch an error and revert change
.catch(function (ex) {
this.setState({
listForUI: this.state.listForUI.cloneWithRows(prevItems)
});
});
}