Более чистый / короткий способ обновить вложенное состояние в Redux?

Для меня полностью закрытие Xcode, а затем перезапуск проекта работал.

Это не решение исходного вопроса, я не верю, но это еще одна простая задача попробовать удаление файлов и папок и т. д. Подтвердите этот ответ для этой идеи.

29
задан Dan Prince 24 February 2016 в 05:32
поделиться

6 ответов

UPD : теперь это часть ES2018.

Его можно немного улучшить с помощью нестандартизированного и все же синтаксиса распространения свойств . :

return {
    ...state,
    notificationBar: {
        ...state.notificationBar,
        open: true,
    },
};
43
ответ дан zerkms 24 February 2016 в 05:32
поделиться

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

Например, я создал библиотеку , где я попытался решить эту проблему следующим образом: я получаю тип модуля (так называемый «тайл»), функцию для выполнения операций ( как асинхронный, так и синхронизированный) и желаемое вложение на основе переданных параметров. Итак, для вашего случая это будет что-то вроде:

import { createSyncTile } from 'redux-tiles';
const uiTile = createSyncTile({
  type: ['ui', 'elements'],
  fn: ({ params }) => params,
  // type will be `notificationBar`
  nesting: ({ type }) => [type],
});

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

0
ответ дан Bloomca 24 February 2016 в 05:32
поделиться

В дополнение к тому, что было сказано ранее, здесь есть функциональный способ с Рамда :

import { assocPath } from 'ramda';

const o1 = { a: { b: { c: 1 }, bb: { cc: 22 } } };
const o2 = assocPath(['a', 'b', 'c'])(42)(o1);
console.log(o1 !== o2, o1.a !== o2.a); // new copies of "changed" objects
console.log(o1.a.bb === o2.a.bb); // deep unchanged properties are copied by reference
0
ответ дан aeldar 24 February 2016 в 05:32
поделиться

Если вы используете Immutable.js , вы можете посмотреть в разделе Вложенные структуры некоторые функции, которые могут вам помочь, я лично использую mergeDeep:

prevState.mergeDeep({ userInfo: {
  username: action.payload.username,
} }),
1
ответ дан Ricardo Mutti 24 February 2016 в 05:32
поделиться

Вы можете использовать линзы.

import { set, makeLenses } from '@DrBoolean/lenses'

const L = makeLenses(['notificationBar', 'open']);
const notificationBarOpen = compose(L.notificationBar, L.open)
const setNotificationBarOpenTrue = set(notificationBarOpen, true)

const a = { notificationBar: { open: false } }
const b = setNotificationBarOpenTrue(a) 
// `a` is left unchanged and `b` is `{ notificationBar: { open: true } }`

Вы можете думать о линзах как о доступе / обновлении композиционных свойств.

Некоторые полезные ресурсы о линзах:

Если у вас все в порядке с чтением lisps , я бы также рекомендовал взглянуть на это превосходное введение в линзы из рэкетной документации . Наконец, если вы хотите пойти глубже и можете читать haskell , вы можете посмотреть: Линзы - композитный доступ к данным и манипулирование ими .

6
ответ дан soundyogi 24 February 2016 в 05:32
поделиться

Хотя можно использовать оператор распространения, существует множество других способов достижения того же результата, даже не требуя будущего компилятора JS для нестандартизированной функции. Вот некоторые другие варианты в произвольном порядке.

Вернуть литерал

Если вы уверены, что ваше состояние не будет расти, тогда вы можете просто вернуть все новое состояние в виде литерала.

return {
  notificationBar: {
    open: true
  }
}

Однако, это не часто будет уместно, потому что маловероятно, что ваше состояние будет таким простым.


Объединить редукторы

Redux предоставляет вам полезный метод для объединения нескольких редукторов, которые работают с различными частями объекта состояния. В этом случае вы бы создали редуктор notificationBar, который обрабатывал бы только этот объект.

 createStore(combineReducers({
   notificationBar: function(state=initialNBarState, action) {
     switch (action.type) {
       case actions.LAYOUT_NOTIFICATIONBAR_OPEN:
         return Object.assign({}, state, { open: true });
   }
 });

Это избавляет вас от необходимости беспокоиться о верхнем уровне свойств, так что вы можете избежать вложенных вызовов в Object.assign.

Если ваше состояние может быть логически разбито на четко определенные разделы, то это, вероятно, самый идиоматический способ решения этой проблемы.


Использование неизменяемых данных

Вы можете использовать библиотеку постоянных структур данных для создания структур данных, которые можно изменить для возврата копии.

Мори

Мори - это результат компиляции структур данных и функционального API Clojure в JS.

import { hashMap, updateIn } from 'mori';

const initialState = hashMap(
  "notificationBar", hashMap(
    "open", false
  )
);

// ...

return updateIn(state, ['notificationBar', 'open'], true);

ImmutableJS

ImmutableJS - это более императивный подход к переносу семантики попыток с отображением хэш-массивов из постоянных структур данных Clojure в Javascript.

import { Map } from 'immutable';

const initialState = Map({
  notificationBar: Map({
    open: true
  });
});

// ...

return state.setIn(['notificationBar', 'open'], true);

Псевдоним Object.assign

Вы можете создать более дружественную версию Object.assign для написания более кратких версий кода выше. Фактически, оно может быть почти таким же кратким, как оператор ....

function $set(...objects) {
  return Object.assign({}, ...objects);
}

return $set(state, {
  notificationBar: $set(state.notificationBar, {
    open: true,
  })
});

Использование неизменяемых помощников

Существует ряд библиотек, которые также предлагают помощники неизменяемости для внесения изменений в обычные изменяемые объекты.

response-addons-update

React уже давно имеет встроенный набор помощников неизменяемости. Они используют синтаксис, аналогичный запросам MongoDB.

import update from 'react-addons-update';

return update(state, {
  notificationBar: {
    open: { $set: true }
  }
});

dot-prop-immutable

Эта библиотека позволяет использовать знакомые пути точек для указания обновлений (вложенных) свойств.

import dotProp from 'dot-prop-immutable';

return dotProp.set(state, 'notificationBar.open', true);

update-in

Эта библиотека является оберткой вокруг react-addons-update и предоставляет более функциональный синтаксис для обновления (вложенных) свойств.

Вместо того, чтобы передавать новое значение, вы передаете функцию, которая принимает старое значение и возвращает новое.

import updateIn from 'update-in';

return updateIn(state, ['notificationBar', 'open'], () => true);

immutable-path

Для обновления свойств эта библиотека похожа на нечто среднее между dot-prop-immutable и update-in.

import path from 'immutable-path';

return path.map(state, 'notificationBar.open', () => true);
46
ответ дан zeckdude 24 February 2016 в 05:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: