В этом посте описывается, как важно не изменять состояние в реакции.

Чтобы понять мутации состояний в реакции, сначала нужно понять основы мутаций данных в javascript.

Если что-то неизменяемое, значит, это не может быть изменено. В javascript есть 5 примитивов. числа, строки, логические значения, undefined и null, они неизменяемы.

Пример1: -

let str = ‘abc’

str нельзя изменить напрямую, поэтому, если мы хотим внести изменения в строку, мы должны использовать такие функции, как replace, toUpperCase и т. д., которые создают новую строку.

Пример2: -

let str1 = ‘abc’
let str2 = ‘abc’

Теперь str1 === str2 вернет true, потому что str1 и str2 имеют одинаковое значение и относятся к одному и тому же примитиву.

Но для объектов это не работает.

let str1 = new String(‘abc’)
let str2 = new String(‘abc’)

str1 === str2 возвращает false, потому что, хотя значения равны, в памяти создаются два разных объекта, поэтому оба они ссылаются на два разных объекта, поэтому это сравнение не удалось при сравнении ссылок.

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

Проблемы с мутациями состояний в react

В документации React упоминается, что никогда не изменяйте this.state напрямую, вместо этого всегда используйте this.setState для любых обновлений состояния. Вот две основные причины для этого:

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

б.) Производительность. При использовании чистого компонента или shouldComponentUpdate они будут выполнять неглубокое сравнение с использованием оператора ===, но если вы измените состояние, ссылка на объект останется прежней, поэтому сравнение не удастся.

Предотвращение мутаций массива / объекта

а.) Используйте фрагмент

let x = [‘a’, ’b’, ’c’, ’d’, ’e’]

Если мы хотим удалить c из приведенного выше массива и распечатать массив, мы можем сделать следующее.

x.splice(2,1)
console.log(x) // prints [‘a’, ’b’, ’d’, ’e’]

но splice напрямую изменил x, поэтому он изменил массив.

Это может быть достигнуто неизменным образом, как показано ниже, с помощью slice и concat, поскольку это неизменяемые операции,

let x = [‘a’, ’b’, ’c’, ’d’, ’e’]
let y = x.slice(0,2).concat(x.slice(3))
console.log(x) // prints original array [‘a’, ’b’, ’c’, ’d’, ’e’]
console.log(y) // prints [‘a’, ’b’, ’d’, ’e’]

б.) Используйте Object.assign

let x = { ‘a’:’Hello’, ‘b’: ‘Hey’ }

Теперь предположим, хотим ли мы изменить значение «а» с «Привет» на «Ура».

Мутабельный путь: -

x.a = «Ура», это напрямую изменит объект, которого мы хотим избежать в реакции, если x принадлежит состоянию.

Неизменяемый способ: -

let y = Object.assign({}, x }// creates a brand new object

y.a = «Ура», теперь y можно использовать для обновления состояния реакции, поскольку оно полностью неизменяемо.

c.) Используйте оператор Spread в ES6.

Функциональность, описанная выше, может быть достигнута с помощью оператора распространения.

let x = { ‘a’:’Hello’, ‘b’: ‘Hey’ }
let y = {…x,’a’:’Hurray’}
console.log(x) // prints { a: ‘Hello’, b: ‘Hey’ }
console.log(y)// prints { a: ‘Hurray’, b: ‘Hey’ }

г) Вложенные объекты

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

let user = {
         profile:{
              address:{
              city: ‘London’
              }
         }
}

Если мы хотим навсегда изменить город из Лондона в Нью-Йорк, нам нужно сделать это, как показано ниже.

{
…state,
    user:{
        …state.user,
        profile:{…state.user.profile,
        address:{…state.user.profile.address, city:’Newyork’}}
    }
}

Вот почему рекомендуется сохранять состояние реакции как можно более плоским, также рассмотрите возможность использования Immutable.js (https://facebook.github.io/immutable-js/), который выполняет неизменяемые изменения данных с помощью встроенных функций или Immutability Helper. как предлагается в документации React (https://reactjs.org/docs/update.html).