【问题标题】:How to optimistically update item in a ListView如何乐观地更新 ListView 中的项目
【发布时间】:2016-02-26 17:48:59
【问题描述】:

我正在制作一个简单的 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,然后更新服务器(最后一部分超出范围的反应本机应用程序).​​. 总而言之,我有一个数据副本,当我进行更改时,我可以对其进行变异,用作ds.cloneWithRows 的数据源

但是,保留一个数据结构的缓存似乎没有多大意义,我可以改变它的唯一目的是使用它作为不可变数据结构的源(下面的代码中的listForUI: ds.cloneWithRows(t))如果我想乐观地更新 UI(即在保存到服务器之前显示更改)。

替代方案(对我来说也没有多大意义)似乎是更新服务器,并在我更新或向列表中添加新项目时等待响应(不保留任何类型的缓存),但这会很慢?

问题:没有保留数据的可变副本作为缓存,有没有办法在 react native 中乐观地更新 ui?

addNewItemToList: function(){

  var t = this.state.items;  //my cache of list items
  var newListItem = {};
  newListItem['id'] = 123;
  t.push(newListItem);  //adding-mutating the cache

  //creating a new immutable ds
  var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
  this.setState({
    listForUI: ds.cloneWithRows(t)
  }, function(){

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

 }

【问题讨论】:

    标签: reactjs react-native


    【解决方案1】:

    不,我很确定没有其他方法可以更新 ListView 数据源,因为正如您所解释的,它是不可变的。不变性意味着您总是需要在添加任何内容之前对其进行复制。

    你提到:

    但是,保留一个数据结构的缓存似乎没有多大意义,我可以改变它的唯一目的是将其用作不可变数据结构的源...

    我不太确定为什么您觉得保留此缓存没有意义。我也不认为这是导致性能问题的原因,因为缓存仅在运行 addNewItemToList 时短暂存在。

    【讨论】:

    • 为什么你认为缓存只存在很短的时间?对于任何类型的更新,您都必须始终保留应用程序的数据副本,然后在每次更新后调用 cloneWithRows 以创建新的不可变副本。
    • 哦,对了,我看错了你原来的帖子。我认为在没有缓存的情况下,唯一可行的方法是您能够访问从dataSource 中取出的原始数据结构,但这似乎是不可能的。
    【解决方案2】:

    如果要撤消乐观更新,则需要存储以前的项目。为此,您需要以某种方式“缓存”或存储对先前数据的引用。

    您可以在addNewItemToList 处理程序中乐观地调用this.setState 并更新您的状态(导致重新渲染),然后在您的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)
             });
         });
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-09-25
      • 1970-01-01
      • 2013-11-10
      • 1970-01-01
      • 2017-11-02
      • 2023-04-11
      • 1970-01-01
      相关资源
      最近更新 更多