Как обновить элемент внутри списка с помощью 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>


обычный веб-разработчик (а не функциональный программист) этого не поймет!



у меня довольно простой (для non-функциональный подход) случае.



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 где элемент с именем третий у его графа значение 4?

581   6  

6 ответов:

наиболее подходящим случаем является использование обоих findIndex и update методы.

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

P. S. Это не всегда возможно использовать карты. Например, если имена не уникальны, и я хочу обновить все элементы с одинаковыми именами.

С .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 метод, который имеет гораздо более простую подпись и документацию:

возвращает новый список с обновленным значением в индексе с возвратом значение вызова updater с существующим значением или notSetValue, если индекс не был установлен.

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

, который, как элемент Map::update docs полагаю, что это "эквивалентно: list.set(index, updater(list.get(index, notSetValue)))".

где элемент с именем "третий"

это не то, как работают списки. Вы должны знать индекс элемента, который вы хотите обновить, или вы должны искать его.

как я могу обновить список, где элемент с именем 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)

объяснение

Обновление Неизменными.коллекции 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) - это значит установить значение 4 по индексу 2.

обновления

пример, который вы дали, имеет вложенные данные. Мы не можем просто использовать set() на первом сборе.

незыблемыми.коллекции js имеют семейство методов с именами, заканчивающимися на "In", которые позволяют вносить более глубокие изменения во вложенные набор. Наиболее распространенные методы обновления имеют связанный метод "In". Например, для set здесь setIn. Вместо того, чтобы принимать индекс или ключ в качестве первого аргумента, эти методы "In" принимают "путь ключа". Путь к ключу-это массив индексов или ключей, который иллюстрирует, как получить значение, которое вы хотите обновить.

в вашем примере вы хотели обновить элемент в списке по индексу 2, а затем значение в ключе "count" внутри этого элемента. Так что ключевой путь будет [2, "count"]. Второй параметр для setIn метод работает так же, как set, это новое значение, которое мы хотим поставить там, так:

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

найти правильный путь к ключу

идя на один шаг дальше, вы на самом деле сказали, что хотите обновить элемент, где название "Три" который отличается от всего 3-го пункта. Например, может быть, ваш список не отсортирован, или, возможно, там элемент с именем "два" был удален ранее? Это означает, что сначала нам нужно чтобы убедиться, что мы действительно знаем правильный путь ключа! Для этого мы можем использовать findIndex() метод (который, кстати, работает почти так же, как массив#findIndex).

после того, как мы нашли индекс в списке, который имеет элемент, который мы хотим обновить, мы можем предоставить ключевой путь к значению, которое мы хотим обновить:

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

Примечание: Set vs Update

в исходном вопросе упоминаются методы обновления, а не набор методы. Я объясню второй аргумент в этой функции (называется updater), так как он отличается от set(). В то время как второй аргумент set() это новое значение, которое мы хотим, второй аргумент update() это функции, которая принимает Предыдущее значение и возвращает новое значение, которое мы хотим. Тогда,updateIn() является" в " вариация update() который принимает ключевой путь.

скажем, например, мы хотели вариант вашего примера, который не просто установил счетчик 4, а вместо увеличивается существующий граф, мы могли бы предоставить функцию, которая добавляет к существующему значению:

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>

можно использовать map:

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

но это будет повторяться по всей коллекции.

Comments

    Ничего не найдено.