Разница между установкой массива, равного другому, или использованием трех точек - PullRequest
2 голосов
/ 14 января 2020

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

const [listCollapsed, setListCollapse] = useState(Array(props.list.length).fill(false));

const expandCollapse = (ind) => {
    let newListCollapsed = listCollapsed;
    newListCollapsed[ind] = !listCollapsed[ind];
    setListCollapse(newListCollapsed);

}

, где expandCollapse был функцией, вызываемой при нажатии на элемент списка. Я обнаружил, что изменение первой строки функции на:

let newListCollapsed = [...listCollapsed];

заставило ее работать. Мне было интересно, чем это объясняется.

1 Ответ

7 голосов
/ 14 января 2020

Ваша первая версия нарушила одно из основных правил React, изменив состояние напрямую (подробнее об этом в этой части документов ). Строка

let newListCollapsed = listCollapsed;

просто заставляет newListCollapsed и listCollapsed оба ссылаться на один и тот же массив (тот, который используется в качестве состояния), не копирует массив. Когда вы сделаете это, вы получите следующее:

state:Ref5461−−−−−−−−−−−−−−−−+
                              \      +−−−−−−−−−−−+ 
listCollapsed:Ref5461−−−−−−−−−−+−−−−>|  (array)  | 
                              /      +−−−−−−−−−−−+ 
newListCollapsed:Ref5461−−−−−+       | 0: false  | 
                                     | 1: false  | 
                                     | ...       | 
                                     +−−−−−−−−−−−+

Так что

setListCollapse(newListCollapsed);

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

Но эта строка:

let newListCollapsed = [...listCollapsed];

копирует массив в новый массив (с использованием нотации распространения, чтобы разложить его записи в новый массив, созданный литералом []), поэтому у вас есть:

state:Ref5461−−−−−−−−−−−−−−−−+
                              \      +−−−−−−−−−−−+ 
listCollapsed:Ref5461−−−−−−−−−−+−−−−>|  (array)  | 
                                     +−−−−−−−−−−−+ 
                                     | 0: false  | 
                                     | 1: false  | 
                                     | ...       | 
                                     +−−−−−−−−−−−+

                                     +−−−−−−−−−−−+ 
newListCollapsed:Ref8465−−−−−−−−−−−−>|  (array)  | 
                                     +−−−−−−−−−−−+ 
                                     | 0: false  | 
                                     | 1: false  | 
                                     | ...       | 
                                     +−−−−−−−−−−−+

Так что, когда вы вызываете setListCollapse(newListCollapsed);, это не то же самое, и изменение делается. Это правильная вещь.

(Значения Ref#### на этих диаграммах являются концептуальными. Это ссылки на объекты для двух массивов. Ссылка на объект сообщает механизму JavaScript, где объект находится в памяти. Вы никогда не увидите фактическое значение ссылки на объект в своем коде.)

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