Реакция - Обновление состояния (массив объектов). Нужно ли глубоко копировать массив? - PullRequest
3 голосов
/ 24 мая 2019

У меня есть следующее state:

const[images,setImages] = useState([
  {src: 'stringSRC1', selected: false},
  {src: 'stringSRC2', selected: false},
  {src: 'stringSRC3', selected: false}
]);

Я обновляю его (переключая выбранное состояние) с помощью этого кода:

function handleImageClick(index) {
  props.setImages((prevState)=>{
    const aux = Array.from(prevState);
    aux[index].selected = !aux[index].selected;
    return aux;
  });
}

Работает как задумано.Но я подумал об одном.

Когда я копирую массив из prevState, Я создаю новый массив, но объекты (сохраненные в виде ссылок) останутся прежними. Я проверял, и они не меняются, когда вы копируете массив таким образом.

ВОПРОС

Это плохая практика?Стоит ли углубляться в копирование массива, как при создании нового массива и создании совершенно новых объектов?Или это просто отлично?

Ответы [ 2 ]

0 голосов
/ 24 мая 2019

Да, вы должны глубоко клонировать, если вы хотите избежать побочных эффектов.

В вашей функции:

function handleImageClick(index) {
  props.setImages((prevState)=>{
    const aux = Array.from(prevState);
    aux[index].selected = !aux[index].selected;
    return aux;
  });
}

При использовании Array.from вы получаете ссылки наобъекты сохранены, поэтому ваш prevState изменен.

См. это:

setTest(prevState => {
      console.log("PrevState", prevState);
      const b = Array.from(prevState);
      b[0].a = b[0].a + 1;
      return b;
    });

Вы можете проверить это здесь:

https://codesandbox.io/embed/exciting-mcnulty-6spdh?fontsize=14

Вы будетеобратите внимание, что prevState имеет следующее значение, поэтому вы теряете значение prevState.

Представьте, что вы хотите сделать это в своем коде:

function handleImageClick(index) {
      props.setImages((prevState)=>{
        const aux = Array.from(prevState);
        aux[index].selected = !aux[index].selected;
        aux[index + 1].selected = prevState[index].selected;
        return aux;
      });
    }

aux[index + 1].selected = prevState[index].selected; не работает !!

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

Вы можете сделать: const aux = JSON.parse(JSON.stringify(prevState));

0 голосов
/ 24 мая 2019

Нет, вот как это должно работать. Да, объекты не меняются, но важно то, что массив изменяется. React выполняет поверхностные сравнения между DOM и виртуальным DOM до того момента, когда все изменилось. Когда ваш новый массив сравнивается со старым, изменение будет обнаружено, содержимое самого массива на самом деле не имеет значения.

...