如何乐观地更新ListView

时间:2016-02-26 17:48:59

标签: reactjs react-native

我正在制作一个简单的反应本机应用程序,它有几个列表,它使用户有机会更新任何列表中的项目或将新项目添加到列表中。

但是,正如之前在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)

2 个答案:

答案 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)
         });
     });
 }