Реакция сравнения состояний с объектами и вложенными массивами - PullRequest
0 голосов
/ 24 сентября 2019

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

Объект, который загружается в состояние с помощью useEffect выглядит так:

{
  active: true,
  design: [
    {
      existing: '55Xgm53McFg1Bzr3qZha',
      id: '38fca',
      options: ['John Smith', 'Jane Doe'],
      required: true,
      title: 'Select your name',
      type: 'Selection List'
    },
   {
      existing: '55Xgm53McFg1Bzr3qZha',
      id: '38fca',
      options: ['John Smith', 'Jane Doe'],
      required: true,
      title: 'Select your name',
      type: 'Selection List'
    },
  ],
  icon: '?',
  id: '92yIIZxdFYoWk3FMM0vI',
  projects: false,
  status: true,
  title: 'Prestarts'
}


Вот так я загружаю в свой объект приложения и определяю состояние компаратора ( previousApp ), чтобы сравнить его и обнаружить изменения (с lodash), все это работаетотлично, пока я не изменю значение в массиве design .

const [app, setApp] = useState(null)
const [edited, setEdited] = useState(false)
const previousApp = useRef(null)

 useEffect(() => {
    if (app === null) {
      getApp(someAppId).then(setApp).catch(window.alert)
    }
    if (previousApp.current === null && app) {
      previousApp.current = { ...app }
    }
    if (previousApp.current && app) {
      _.isEqual(app, previousApp.current) ? setEdited(false) : setEdited(true)
    }
  }, [app])

Например, я изменяю входное значение app.design [0] .title = 'testing' со следующим кодом:

const updateItem = e => {
  let newApp = { ...app }
  let { name, value } = e.target
  newApp.design[0][name] = value
  setApp(newApp)
}

Это работает в том смысле, что онообновляет объект состояния моего приложения, но не обнаруживает каких-либо изменений по сравнению с previousApp.current

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


Перестановка массива design работает, как ожидается, и обнаруживает изменение с помощью следующей функции:

const updateDesign = e => {
  let newApp = { ...app }
  newApp.design = e
  setApp(newApp)
}

Ответы [ 2 ]

2 голосов
/ 24 сентября 2019

Вероятно, он не обнаружил никакой разницы, поскольку массив , присутствующий в свойстве design, сохранял ту же ссылку.

Когда вы делаете это:

let newApp = { ...app }

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

Я думаю, это также решит вашу проблему:

const updateItem = e => {
  let newApp = { ...app };
  let newDesign = Array.from(app.design);  // THIS CREATES A NEW ARRAY REFERENCE FOR THE 'design' PROPERTY
  let { name, value } = e.target;
  newDesign[0][name] = value;
  setApp({
    ...newApp,
    design: newDesign
  });
}
0 голосов
/ 24 сентября 2019

Я обнаружил, что с помощью функции lodash cloneDeep я смог удалить странную связь, которая возникала между предыдущими App и App;Хотя я использовал {... app}

См. Следующее:

if (previousApp.current === null && app) {
   previousApp.current = cloneDeep(app)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...