it-swarm.com.ru

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

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

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

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?

122
Vitalii Korsakov

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

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

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

114
Vitalii Korsakov

С . 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);

Надеюсь, поможет!

27
Albert Olivé

Вот что сказали официальные документы ... updateIn

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

Возвращает новый список с обновленным значением по индексу с возвращаемым значением вызывающего средства обновления с существующим значением или 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)))".

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

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

Как я могу обновить список, в котором элементу с именем третье установлено число 4?

Это должно сделать это:

list = list.update(2, function(v) {
    return {id: v.id, name: v.name, count: 4};
});
18
Bergi
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);

Теперь, если мы хотим обновить третий элемент, простой массив JS может выглядеть следующим образом: counts[2] = 4. Поскольку мы не можем использовать мутацию и должны вызывать метод, вместо этого мы можем использовать: counts.set(2, 4) - это означает установить значение 4 в индексе 2.

Глубокие обновления

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

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

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

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

Поиск правильного ключевого пути

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

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

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

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

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

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

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

Используйте . 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>
9
Meistro

Мне очень нравится этот подход с сайта 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);
0
Dryden Williams