Как работает мелкий анализ в реакции

В этой документации Реакта говорится, что

shallowCompare выполняет проверку неглубокого соответствия текущим объектам реквизита и nextProps, а также текущим состояниям и объектам nextState.

Вещь, которую я не могу понять, - это если она неглубоко сравнивает объекты, то метод метода CompompententUpdate всегда будет возвращать true, так как

Мы не должны мутировать состояния.

и если мы не будем мутировать состояния, тогда сравнение всегда будет возвращать false, и поэтому updateContonent всегда будет возвращать true. Я запутался в том, как он работает, и как мы переопределим это, чтобы повысить производительность.

Ответ 1

Неглубокое сравнение проверяет равенство. При сравнении скалярных значений (чисел, строк) он сравнивает их значения. При сравнении объектов он не сравнивает свои атрибуты - сравниваются только их ссылки (например, "указывают ли они на один и тот же объект?").

Рассмотрим следующую форму объекта user

user = {
  name: "John",
  surname: "Doe"
}

Пример 1:

const user = this.state.user;
user.name = "Jane";

console.log(user === this.state.user); // true

Обратите внимание, что вы изменили имя пользователя. Даже с этими изменениями объекты равны. Эти ссылки точно такие же.

Пример 2:

const user = clone(this.state.user);
console.log(user === this.state.user); // false

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

Функция Clone может выглядеть так (синтаксис ES6)

const clone = obj => Object.assign({}, ...obj);

Малое сравнение - эффективный способ обнаружения изменений. Он ожидает, что вы не будете мутировать данные.

Ответ 2

неглубокое сравнение - это когда свойства сравниваемых объектов выполняются с использованием "===" или строгого равенства и не будут проводить сравнения глубже в свойствах. например,

// a simple implementation of the shallowCompare.
// only compares the first level properties and hence shallow.
// state updates(theoretically) if this function returns true.
function shallowCompare(newObj, prevObj){
    for (key in newObj){
        if(newObj[key] !== prevObj[key]) return true;
    }
    return false;
}
// 
var game_item = {
    game: "football",
    first_world_cup: "1930",
    teams: {
         North_America: 1,
         South_America: 4,
         Europe: 8 
    }
}
// Case 1:
// if this be the object passed to setState
var updated_game_item1 = {
    game: "football",
    first_world_cup: "1930",
    teams: {
         North_America: 1,
         South_America: 4,
         Europe: 8 
    }
}
shallowCompare(updated_game_item1, game_item); // true - meaning the state
                                               // will update.

Хотя оба объекта кажутся одинаковыми, game_item.teams - это не та же ссылка, что и updated_game_item.teams. Для того, чтобы 2 объекта были одинаковыми, они должны указывать на один и тот же объект. Таким образом, это приводит к тому, что оцениваемое состояние обновляется

// Case 2:
// if this be the object passed to setState
var updated_game_item2 = {
    game: "football",
    first_world_cup: "1930",
    teams: game_item.teams
}
shallowCompare(updated_game_item2, game_item); // false - meaning the state
                                               // will not update.

На этот раз каждое из свойств возвращает true для строгого сравнения, поскольку свойство команд в новом и старом объекте указывает на тот же объект.

// Case 3:
// if this be the object passed to setState
var updated_game_item3 = {
    first_world_cup: 1930
}
shallowCompare(updated_game_item3, game_item); // true - will update

Свойство updated_game_item3.first_world_cup не соответствует строгой оценке, поскольку 1930 - это число, а game_item.first_world_cup - строка. Если бы сравнение было свободным (==), это прошло бы. Тем не менее это также приведет к обновлению состояния.

Дополнительные замечания:

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

Ответ 3

Существует также унаследованное объяснение неглубокого сравнения в React:

shallowCompare выполняет проверку неглубокого соответствия текущим объектам реквизита и nextProps, а также текущим состояниям и объектам nextState.

Он делает это путем итерации по клавишам сравниваемых объектов и возвращает true, когда значения ключа в каждом объекте не являются строго равными.

UPD: Текущая документация говорит о неглубоком сравнении:

Если ваша функция React component render() отображает тот же результат при одинаковых реквизитах и состоянии, вы можете использовать React.PureComponent для повышения производительности в некоторых случаях.

React.PureComponent shouldComponentUpdate() только мелко сравнивает объекты. Если они содержат сложные структуры данных, это может привести к ложным отрицаниям для более глубоких различий. Расширяйте PureComponent только тогда, когда вы ожидаете наличия простых реквизитов и состояний, или используйте forceUpdate(), когда вы знаете, что глубокие структуры данных изменились

UPD2: Я считаю, что примирение также является важной темой для понимания неглубокого сравнения.

Ответ 4

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

Ответ 5

shallowCompare выполняет проверку неглубокого соответствия текущим объектам реквизита и nextProps, а также текущим состояниям и объектам nextState. Он делает это путем итерации по клавишам сравниваемых объектов и возвращает true, когда значения ключа в каждом объекте не являются строго равными.

shallowCompare возвращает true, если нечеткое сравнение для реквизита или состояния не выполняется, и поэтому компонент должен обновляться. shallowCompare возвращает false, если мелкое сравнение для реквизита и состояния проходит, и поэтому компонент не нуждается в обновлении.

    export class SampleComponent extends React.Component {

  shouldComponentUpdate(nextProps, nextState) {

    return shallowCompare(this, nextProps, nextState);
  }

  render() {

    return <div className={this.props.className}>foo</div>;

  }
}

Ответ 6

Неглубокий равный фрагмент кода @supi выше (fooobar.com/info/6549321/...) завершается ошибкой, если prevObj имеет ключ, newObj нет у newObj. Вот реализация, которая должна учитывать это:

const shallowEqual = (objA, objB) => {
  if (!objA || !objB) {
    return objA === objB
  }
  return !Boolean(
    Object
      .keys(Object.assign({}, objA, objB))
      .find((key) => objA[key] !== objB[key])
  )
}

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