Как предотвратить изменение зависимости объекта, который передается в качестве параметра, без повторного клонирования каждый раз

#javascript #typescript

#javascript #typescript

Вопрос:

Допустим, у меня есть объект данных, который является моим «состоянием». Возьмем пример цветов и то, как они соотносятся друг с другом соответственно.

 const data = {
   colors: [
     {id: 1, name: "black", hex: "#000"},
     {id: 2, name: "white", hex: "#fff"},
     {id: 3, name: "grey", hex: "#bbb"}
   ],
   relations: [
     {id: 1, from: 3, to: 1},
     {id: 2, from: 3, to: 2},
   ]
}
  

Этот объект данных поддерживается и обновляется в моем коде с помощью таких функций, как removeColor , addColor , filterColors , и я передаю его в зависимость для отображения в виде графика.

Проблема в том, что зависимость изменяет мой собственный объект данных, который я передал.Он добавит свои собственные свойства и изменит некоторые из моих для своих графических целей.

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

 {id: 12, name: 'black', hex: "#000", x: 500, y:500, z: 0.05, hidden: false},

  

Он не только переопределяет мой собственный идентификатор, но и добавляет значения к объекту.

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


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

т.е. если я добавляю show: false в свой элемент grey , мне нужно сделать то же самое с клонированным объектом данных, мне нужно получить доступ к grey элементу в массиве цветов и добавить show: false .

Ответ №1:

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

Хотя я думаю, что это отвечает на ваш вопрос, имейте в виду, что это может нарушить вашу зависимость. Если зависимость устанавливает переменную, а затем это не ожидаемое значение, возможно, это сбой (например, если он использует идентификатор для внутренних целей).

Тем не менее, вот пример использования прокси в вашем сценарии:

 const data = {
   colors: [
     {id: 1, name: "black", hex: "#000"},
     {id: 2, name: "white", hex: "#fff"},
     {id: 3, name: "grey", hex: "#bbb"}
   ],
   relations: [
     {id: 1, from: 3, to: 1},
     {id: 2, from: 3, to: 2},
   ]
}

const createHandler = (obj) => {
  return {
    get(target, prop, receiver) {
      const val = obj[prop]
      // If the value is an object, we return another proxy
      // so the dependency also has no access to nested properties
      return typeof val === 'object' ? new Proxy(val, createHandler(val)) : val
    },
    set(target, prop, receiver) {
      // no-op
    }
  }
}

// proxy passed to dependency
proxy = new Proxy(data, createHandler(data))

console.log('initial value', proxy.relations[0].id)
proxy.relations[0].id = 10
console.log('after proxy writing', proxy.relations[0].id)
data.relations[0].id = 10
console.log('after original writing', proxy.relations[0].id)  

Комментарии:

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

2. да, я так думаю. в настоящее время set(...) метод ничего не делает, поэтому свойство не задано. Если вы хотите разрешить добавление новых свойств, вы можете проверить, содержит ли исходный объект prop. Если да, ничего не делайте. Если нет, установите свойство.

3. Также примечание: зависимость, которая имеет такие непреднамеренные побочные эффекты, звучит странно. Я бы посоветовал вам рассмотреть возможность изменения зависимости или заменить ее на другую