繁体   English   中英

如何使用ImmutableJS更新List中的元素?

[英]How to update element inside List with ImmutableJS?

这是官方文档所说的

updateIn(keyPath: Array<any>, updater: (value: any) => any): List<T>
updateIn(keyPath: Array<any>, notSetValue: any, updater: (value: any) => any): List<T>
updateIn(keyPath: Iterable<any, any>, updater: (value: any) => any): List<T>
updateIn(keyPath: Iterable<any, any>, notSetValue: any, updater: (value: any) => any): List<T>

普通的Web开发人员(非功能程序员)无法理解这一点!

我非常简单(对于非功能性方法)的情况。

var arr = [];
arr.push({id: 1, name: "first", count: 2});
arr.push({id: 2, name: "second", count: 1});
arr.push({id: 3, name: "third", count: 2});
arr.push({id: 4, name: "fourth", count: 1});
var list = Immutable.List.of(arr);

如何更新list ,其中名称为third的元素的计数设置为4

最合适的情况是使用findIndexupdate方法。

list = list.update(
  list.findIndex(function(item) { 
    return item.get("name") === "third"; 
  }), function(item) {
    return item.set("count", 4);
  }
); 

PS并不总是可以使用地图。 例如,如果名称不唯一,我想更新具有相同名称的所有项目。

使用.setIn()可以执行相同的操作:

let obj = fromJS({
  elem: [
    {id: 1, name: "first", count: 2},
    {id: 2, name: "second", count: 1},
    {id: 3, name: "third", count: 2},
    {id: 4, name: "fourth", count: 1}
  ]
});

obj = obj.setIn(['elem', 3, 'count'], 4);

如果我们不知道要更新的条目的索引。 使用.findIndex()很容易找到它:

const indexOfListToUpdate = obj.get('elem').findIndex(listItem => {
  return listItem.get('name') === 'third';
});
obj = obj.setIn(['elem', indexOfListingToUpdate, 'count'], 4);

希望能帮助到你!

这是官方文档说的...... updateIn

您不需要updateIn ,仅适用于嵌套结构。 您正在寻找update方法 ,它具有更简单的签名和文档:

返回一个新的List,其索引处的更新值为使用现有值调用updater的返回值,如果未设置index,则返回notSetValue。

 update(index: number, updater: (value: T) => T): List<T> update(index: number, notSetValue: T, updater: (value: T) => T): List<T> 

正如Map::update文档所暗示的那样,它“ 等同于: list.set(index, updater(list.get(index, notSetValue))) ”。

其中名称为“third”的元素

这不是列表的工作方式。 您必须知道要更新的元素的索引,或者您必须搜索它。

如何更新列表,其中名称为third的元素的计数设置为4?

这应该这样做:

list = list.update(2, function(v) {
    return {id: v.id, name: v.name, count: 4};
});
var index = list.findIndex(item => item.name === "three")
list = list.setIn([index, "count"], 4)

说明

更新Immutable.js集合始终返回这些集合的新版本,而原始集合保持不变。 因此,我们不能使用JavaScript的list[2].count = 4变异语法。 相反,我们需要调用方法,就像我们可能使用Java集合类一样。

让我们从一个更简单的例子开始:只是列表中的计数。

var arr = [];
arr.push(2);
arr.push(1);
arr.push(2);
arr.push(1);
var counts = Immutable.List.of(arr);

现在,如果我们想要更新第3项,那么普通的JS数组可能看起来像: counts[2] = 4 由于我们不能使用变异,并且需要调用方法,而是我们可以使用: counts.set(2, 4) - 这意味着在索引2处设置值4

深度更新

您给出的示例包含嵌套数据。 我们不能只在初始集合上使用set()

Immutable.js集合有一系列方法,名称以“In”结尾,允许您在嵌套集中进行更深层次的更改。 最常见的更新方法具有相关的“In”方法。 例如,对于setsetIn 这些“In”方法不接受索引或键作为第一个参数,而是接受“关键路径”。 关键路径是索引或键的数组,用于说明如何获取要更新的值。

在您的示例中,您希望更新索引2中列表中的项目,然后更新该项目中键“count”的值。 所以关键路径是[2, "count"] setIn方法的第二个参数就像set一样工作,它是我们想要放在那里的新值,所以:

list = list.setIn([2, "count"], 4)

找到正确的关键路径

更进一步,你实际上说你想要更新名称为“3”的项目,这与第3项不同。 例如,您的列表可能没有排序,或者可能之前删除了名为“two”的项目? 这意味着首先我们需要确保我们确实知道正确的关键路径! 为此我们可以使用findIndex()方法(顺便说一句,它的工作方式几乎与Array#findIndex一样 )。

一旦我们在列表中找到了包含我们想要更新的项目的索引,我们就可以提供我们希望更新的值的关键路径:

var index = list.findIndex(item => item.name === "three")
list = list.setIn([index, "count"], 4)

注意: SetUpdate

原始问题提到了更新方法而不是set方法。 我将解释该函数中的第二个参数(称为updater ),因为它与set()不同。 而第二个参数set()是我们希望新的价值,第二个参数来update()是接受于前值和返回,我们希望新的值的函数 然后, updateIn()update()的“In”变体,它接受一个键路径。

比方说,我们想要一个不仅将计数设置为4示例变体,而是增加现有计数,我们可以提供一个函数,将现有值加1:

var index = list.findIndex(item => item.name === "three")
list = list.updateIn([index, "count"], value => value + 1)

使用.map()

list = list.map(item => 
   item.get("name") === "third" ? item.set("count", 4) : item
);

 var arr = []; arr.push({id: 1, name: "first", count: 2}); arr.push({id: 2, name: "second", count: 1}); arr.push({id: 3, name: "third", count: 2}); arr.push({id: 4, name: "fourth", count: 1}); var list = Immutable.fromJS(arr); var newList = list.map(function(item) { if(item.get("name") === "third") { return item.set("count", 4); } else { return item; } }); console.log('newList', newList.toJS()); // More succinctly, using ES2015: var newList2 = list.map(item => item.get("name") === "third" ? item.set("count", 4) : item ); console.log('newList2', newList2.toJS()); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.js"></script> 

我非常喜欢thomastuts网站上的这种方法:

const book = fromJS({
  title: 'Harry Potter & The Goblet of Fire',
  isbn: '0439139600',
  series: 'Harry Potter',
  author: {
    firstName: 'J.K.',
    lastName: 'Rowling'
  },
  genres: [
    'Crime',
    'Fiction',
    'Adventure',
  ],
  storeListings: [
    {storeId: 'amazon', price: 7.95},
    {storeId: 'barnesnoble', price: 7.95},
    {storeId: 'biblio', price: 4.99},
    {storeId: 'bookdepository', price: 11.88},
  ]
});

const indexOfListingToUpdate = book.get('storeListings').findIndex(listing => {
  return listing.get('storeId') === 'amazon';
});

const updatedBookState = book.setIn(['storeListings', indexOfListingToUpdate, 'price'], 6.80);

return state.set('book', updatedBookState);

你可以使用map

list = list.map((item) => { 
    return item.get("name") === "third" ? item.set("count", 4) : item; 
});

但这将遍及整个集合。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM