Почему состояние меняется, если я использую оператор распространения? - PullRequest
1 голос
/ 05 мая 2019

У меня есть этот код, который я тестирую на jsfiddle

onVote = (dir, index) => {        
    console.log(this.state)

    const products = [...this.state.products]           
    products[index].votes = dir ? products[index].votes + 1 : products[index].votes - 1

    console.log(this.state.products[index].votes)
    // this.setState({products})
  };

https://jsfiddle.net/hkL3wug7/2/

Однако, хотя я не устанавливаю State, журнал консоли показывает, что состояние меняется каждый раз, когда я нажимаю на знаки плюс и минус.

Я сделал так же, как в этой статье https://medium.com/@giltayar/immutably-setting-a-value-in-a-js-array-or-how-an-array-is-also-an-object-55337f4d6702

const newState = [...state] // clone the array
      newState[action.index].done = true
      return newState

насколько я понимаю

(это не дубликат другого вопроса, я не прошу эффективного способа)

Ответы [ 2 ]

3 голосов
/ 05 мая 2019

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

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

// Shallow copy of the array
const products = [...this.state.products];

// Shallow copy of the object within the array
const updatedProduct = { ...products[index] };

// Update the copy of the object
updatedProduct.votes = dir ? updatedProduct.votes + 1 : updatedProduct.votes - 1;

// Replace the object with the updated copy
products[index] = updatedProduct;
1 голос
/ 05 мая 2019

Как упомянуто в комментарии @Carcigenicate, использование оператора распространения создает поверхностную копию массива. Это создает проблему для вас, потому что расширенная версия массива содержит Object s, которые передаются по ссылке. Поэтому, хотя ваша локальная переменная products является новой копией this.state.products, они обе содержат ссылки на одни и те же Object s.

Чтобы достичь того, что вы пытаетесь сделать, вам нужно клонировать объекты в this.state.products. Один из возможных способов сделать это - использовать Object.assign и заменить const products = [...this.state.products] на:

const products = [
    Object.assign({}, this.state.products.Orange),
    Object.assign({}, this.state.products.Apples),
    Object.assign({}, this.state.products.Bananas)
]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...