Состояние утверждений селектора React & Reselect осталось прежним после обновления

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

Мой селектор:

const getBaseInfo = (state) => state.Info;
const getResources = (state) => state.Resources;

export const ASelector = createSelector(
  [getBaseInfo, getResources],
  (items, resources) => { 
    let result = {};
    for(const item in items) {
      console.log(item);
      result[item] = _.pick(items[item], ['Title', 'Type', 'Beginning', 'minAmount', 'Address'])
    }
    for(const item in resources) {
      console.log(item);
      result[item] = {...result[item], firstImage: resources[item].firstImage}
    }
    return result;
  }
);

Компонент mapStateToProps:

function mapStateToProps(state) {
  console.log(state);
  return { 
    gridInfo: ASelector(state)
  }
}

Сначала мое исходное состояние:

state = { Info: {}, Resources: {} }

Мой редуктор:

const Info = ArrayToDictionary.Info(action.payload.data.Info);
  const Resources = ArrayToDictionary.Resources(action.payload.data.Info);
  let resourcesKeys = Object.keys(Resources);
  let infoKeys = Object.keys(Info);
  let temp = { ...state };
  let newInfo;

  for (let item of infoKeys) {
    newInfo = {
      Title: Info[item].Title,
      Type: Info[item].Type,
      BeginningOfInvesting: Info[item].BeginningOfInvesting,
      DateOfEstablishment: Info[item].DateOfEstablishment,
      pricePerUnit: Info[item].PricePerUnit,
      minUnits: Info[item].MinUnits,
      publicAmount: Info[item].PublicAmount,
      minInvestmentAmount: Info[item].MinInvestmentAmount,
      EinNumber: Info[item].EinNumber,
      Address: Info[item].Address,
      Status: Info[item].Status,
      Lat: Info[item].Lat,
      Lng: Info[item].Lng,
      CurrencySymbol: Info[item].CurrencySymbol,
      Publicity: Info[item].Publicity
    }
    temp.Info[item] = { ...temp.Info[item], ...newInfo }
  }
  for (let item of resourcesKeys) {
    temp.Resources[item] = { ...temp.Resources[item], ...Resources[item] }
  }
  return temp;

Когда компонент рендерится с начальным состоянием, у меня есть действие, извлекающее данные из api и сохраняющее их соответственно в состоянии внутри редукторов.

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

Что-то не так с моими селекторами?

Я действительно пытался использовать его, как указано в документации, но до сих пор не могу понять, как решить мою маленькую проблему.

Большое спасибо за чтение и помощь!


person Kiper    schedule 05.09.2018    source источник
comment
Можете ли вы разместить свои редукторы для срезов state.Info и state.Resources? Это звучит так, как будто ваши редукторы изменяют состояние, а не обновляют его постоянно.   -  person markerikson    schedule 05.09.2018
comment
@markerikson Спасибо за ответ. Только что добавил редуктор. Может быть, вы можете что-то указать, но я использую es6 spread и возвращаю новый объект.   -  person Kiper    schedule 06.09.2018


Ответы (1)


Похоже, что строки temp.Info[item] и temp.Resources[item] изменяют существующее состояние. Вы сделали неглубокую копию верхнего уровня, но неправильно копируете второй уровень. См. Страницу Неизменяемые шаблоны обновления в документации Redux, чтобы объяснить, почему это проблема. и что делать вместо этого.

Вы можете попробовать использовать библиотеку immer, чтобы упростить неизменяемую логику обновления. Кроме того, наша новая библиотека redux-starter-kit внутренне использует Immer.

person markerikson    schedule 06.09.2018
comment
Спасибо за ответ. Я установил immer и, пытаясь его использовать, обнаружил, что моя библиотека redux-persist изменяет состояние, добавляя ._persist, который возвращает исключение, потому что draft не расширяется. Вы что-нибудь знаете об этом? - person Kiper; 09.09.2018
comment
Прочитав статью, я смог успешно заставить селектор работать. Но иммер по-прежнему не работает. - person Kiper; 09.09.2018
comment
У меня была аналогичная проблема, и ваш ответ помог. Я копировал массив, используя синтаксис распространения, но это была неглубокая копия, и, следовательно, когда я обновлял его, я изменял состояние. Дох! (и это не первый раз, когда я это делаю). Клон ЛодашаDeep пришел мне на помощь. Оставив это здесь для всех, у кого такая же проблема (или для себя в будущем;)) - person Ben Smith; 12.04.2019
comment
использование lodash формы deepClone определенно будет работать, его можно использовать, если производительность не является сверхкритичной для приложения, поскольку клонирование всего объекта требует некоторой вычислительной мощности и времени, но для обычных случаев использования это вариант, если кто-то не понимает другого концепции. - person newbie; 30.04.2021
comment
Глубокое клонирование неправильный ответ здесь, потому что это приведет к ненужному повторному рендерингу. Кроме того, это обходной путь, очень похожий на добавление случайного setTimeouts для исправления ошибок синхронизации. Пожалуйста, не делай этого. - person markerikson; 02.05.2021