Клонированные массивы, влияющие на состояние реакции - PullRequest
0 голосов
/ 20 июня 2020

У меня проблемы с клонированием массивов в моем приложении реакции.

Я импортирую массив с данными в свое приложение под названием ApplicationsData. Это массив объектов.

import ApplicationsData from '../Store/Applications';

Компонент приложения имеет следующее состояние:

constructor(props) {
    super(props);    
    this.state = { 
        isOn: true,
        untouchedApplications: [...ApplicationsData],
        applications: [...ApplicationsData],
        activeWindows: [...defaultActive],
        background: "#3a6ea5"
    };
}

Я делаю клон массива с данными, используя оператор распространения «...».

В моем контексте у меня есть метод openApp, который изменяет свойство в элементе в state.applications.

openApp: (appID) => {
                let appIndex = this.state.applications.findIndex( el => el.id == appID);
                let clone = [...ApplicationsData];
                
                clone[appIndex].isActive = true;
                clone[appIndex].newProp = true;
                clone[appIndex].isMinimized = false;
                this.setState({applications: clone})
            },

Каждый раз, когда я попадаю в clone[appIndex].prop = value как state.applications, так и untouchedApplications переопределяется этими данными, несмотря на использование операторов распространения как в состоянии, так и в openApp. Массив untouchedApplications в состоянии не используется нигде в приложении или методе, но также обновляется. Кроме того, свойство newProp, назначенное клонированному массиву, отсутствует в исходном массиве с данными, но применяется к обоим массивам в состоянии после добавления его в клонированный массив.

Я также пробовал использовать Array.from и state.applications.slice() для создания клонов. Я чувствую себя здесь немного потерянным, так как был уверен, что это правильный способ клонирования массивов.

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

Ответы [ 2 ]

1 голос
/ 21 июня 2020

Массивы, с которыми вы работаете, представляют собой массивы объектов. Объекты являются ссылочными типами, что означает, что на самом деле ваши массивы содержат ссылки на объекты.

Когда вы распределяете массив в новый массив, вы не клонируете объекты, а только их ссылки , поэтому, когда вы пишете clone[appIndex], вы ссылаетесь на тот же объект, который содержится в обоих массивах .

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

const newArray = ApplicationsData.map(
  (item, index) =>
    index == appIndex ?
      ({
         ...item,
         isActive: true,
         newProp: true,
         isMinimized: false
       }) : 
    item
);

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

1 голос
/ 21 июня 2020

вам следует использовать map функцию

(appID) => {
   let clone = this.state.applications.map(item => {
        if (item.id == appId) {
            return {
                ...item,
                isActive: true,
                newProp: true,
                isMinimized: false
            }
        }
        return item;
    })    
    this.setState({applications: clone})
},

Это происходит потому, что при использовании оператора ... он создает мелкую копию массива, а не глубокую копию.

let val = [{key: "value"}, {key: "value"}, {key: "value"}]
let copy = [...val];


let isEqualShallow = val[0] == copy[0]

console.log(isEqualShallow)

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

    let val = [{key: "value"}, {key: "value"}, {key: "value"}]
    let copy = val.map(item => {
      return {...item}
    })


    let isEqualDeep = val[0] == copy[0]

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