Как предотвратить повторный рендеринг компонента при использовании redux/reselect?

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

Компоненты A и B создаются одинаково, компонент A имеет ключи значений ['скорость', 'время'], а компонент В не имеет ключей значений [].

Когда скорость и время обновляются, к каждому массиву добавляется еще одно значение, компонент A перерисовывается, как и ожидалось, но компонент B также перерисовывается.

Я думаю, что это происходит из-за изменения ввода valuesSelector для ссылки makeValuesSelector? Хотя значение представляет собой пустой массив.

Есть ли способ предотвратить повторный рендеринг компонента B в этом сценарии?

Состояние

{
 speed: [ 5, 4, 6],
 time: [ 1, 2, 3]
}

ValueKeys

[ 'speed', 'time']

Селектор

const valuesSelector = state => state.values;
const keysSelector= (state, props) => props.valueKeys;

const makeValuesSelector = () =>
  createSelector(
    [valuesSelector, keysSelector],
    (values, keys) => {
      let usedValues = {};
      keys.forEach(key => {
        if (values[key]) {
          usedValues[key] = values[key];
        }
      });
      return usedValues;
    }
  );

Составная часть

const makeMapStateToProps = () => {
  const valuesSelector = makeValuesSelector();
  const mapStateToProps = (state, props) => ({
    values: valuesSelector(state, props),
  });
  return mapStateToProps;
};

person JP4    schedule 26.05.2019    source источник
comment
что такое компонент А и компонент Б?   -  person Joseph D.    schedule 27.05.2019
comment
Экземпляр компонента, который использует MakeMapStateToProps — просто пытался ограничить объем кода в вопросе.   -  person JP4    schedule 27.05.2019
comment
Вы используете makeMapStateToProps как в A, так и в B?   -  person Tomer    schedule 27.05.2019
comment
Да, используя его в обоих.   -  person JP4    schedule 27.05.2019


Ответы (1)


Через некоторое время я вернулся к этой проблеме, так как она вызывала значительное снижение производительности. Я решил эту проблему, используя пользовательскую проверку на равенство в селекторе, чтобы проверить, изменились ли объекты внутри состояния.

Если объекты, требуемые компонентом, не изменились внутри состояния, то makeValuesSelector не запустится из-за того, что этому препятствует пользовательская проверка на равенство. Поскольку makeValuesSelector не был запущен, это предотвратит повторный рендеринг компонента. Что касается случая, который я описал выше, компонент B не будет перерисовываться.

const valuesSelector = state => state.values;
const keysSelector= (state, props) => props.valueKeys;

const equalityCheckShallow = (currentVal, previousVal) => {
  let noUpdate = true;
  Object.keys(currentVal).forEach(key => {
    if (currentVal[key] !== previousVal[key]) {
      noUpdate = false;
    }
  });
  return noUpdate;
};

const createSelectorWithShallowCompare = createSelectorCreator(defaultMemoize, equalityCheckShallow);

const makeValuesSelector = () =>
  createSelectorWithShallowCompare(
    [valuesSelector, keysSelector],
    (values, keys) => {
      let usedValues = {};
      keys.forEach(key => {
        if (values[key]) {
          usedValues[key] = values[key];
        }
      });
      return usedValues;
    }
  );

Надеюсь, это может помочь кому-то в будущем.

person JP4    schedule 25.02.2020