Странное поведение при деструкции в React

#javascript #reactjs #destructuring

Вопрос:

У меня есть глубоко вложенный объект JSON в качестве состояния, изначально созданного с помощью крючка useState —

 
 const [template, setTemplate] = useState([
    {
      
      statement: 'this is top level statement',
      nestingLevel: 0,
      children: [
        {
          nestingLevel: 1,
          statement:
            'this is a statement with such a template',
          children: [
            { 
              statement: 'first chart',
              nestingLevel: 2,
            },
            { statement: 'second chart',
              nestingLevel: 2,
            },
          ],
        },
      ],
    },
    {
     
      statement:
        'this is second statement for section with such a metric {{}}',
      nestingLevel: 0,
      
    },
  ]);

 

У меня есть элемент ввода с обработчиком onChange.

Как вы можете видеть, всякий раз, когда во входном тексте происходят какие-либо изменения, я обновляю некоторую соответствующую пару ключ-значение на основе пути. Я делаю это с помощью функций get и set библиотеки lodash.

 
 const handleDataChange = (e, path) => {
        console.log('handling the data');
        // copy the template
        let templateCopy = template;
        // create the new object with updated information
        const tempObj = _.set(
          templateCopy,
          `${path}['statement']`,
          e.target.value,
        );

        setTemplate([...tempObj]);
      };
 

Проблема заключается в функции handleDataChange. Когда я это делаю setTemplate(tempObj) , состояние не обновляется. Однако, когда я это сделаю setTemplate([...tempObj]) (что, по сути, даст тот же результат), это более позднее решение будет работать так, как ожидалось.

Я хочу знать, почему это так. Связано ли это с тем, что lodash всегда дает результаты в качестве объекта, а деструкция и переупаковка делают его массивом снова, и, следовательно, он работает так, как ожидалось?

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

1. » // создайте новый объект с обновленной информацией » это неверно, _.set приведет к изменению переданного в него объекта, а также к его возврату. tempObj является тем же объектом, templateCopy что и . И templateCopy уже является тем же объектом, template что и . В этой функции нет копий.

2. рассмотрите возможность использования github.com/immerjs/immer для таких обновлений

3. @VLAZ спасибо, что указал на это. Как лучше всего это сделать при использовании функций lodash? Я могу проверить и сообщить вам, работает ли это. Кроме того, почему работает разрушающее решение?

Ответ №1:

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

Вы можете deepClone изменить объект, затем изменить его, как вы это делаете, set а затем обновить состояние.

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

1. Для этого у Lodash есть функция cloneDeep () . Спасибо, что указали на это. Работает, как и ожидалось, без дополнительного деструктурирования и обхода массива.