UseState вообще не работает с Object of Arrays

У меня есть объект useState, который объявлен так в начале файла.

const [comments, setComments] = useState({
  step_up: [],        toe_walking: [],
  toe_touches: [],    squat: [],
  side_to_side: [],   rolling: [],
  leg_lifts: [],      hand_to_knees: [],
  floor_to_stand: [], chair_elevation: [],    
  jumping_jacks: [],  jump_rope: [],
  bear_crawl: []
})

И в состоянии отдачи у меня есть множество comment объектов. Я хочу назначить каждый комментарий соответствующей теме. Комментарий step_up попадет в массив step_up внутри объекта comments. Я делаю это через useEffect, но абсолютно ничего не происходит.

useEffect(() => {
  let allComments = selectedClient.plan.comments
  for( let i = 0; i < selectedClient.plan.comments.length; i ++) {
    let tag = allComments[i].videoId
    console.info(tag)
    if (comments[tag]) {
      let newArr = [...comments[tag]]
      newArr.push(allComments[i])
      let newObj = { ...comments }
      newObj[tag] = newArr
      setComments(comments => ({ ...newObj }))
    }
  }
  setLoading(false)
}, [selectedClient])

Моя консоль подтверждает, что все videoIdдействительны, поскольку журналы показывают следующее:

LOG  step_up
LOG  step_up
LOG  bear_crawl
LOG  bear_crawl
LOG  jumping_jacks
LOG  jump_rope
LOG  hand_to_knees
LOG  side_to_side
LOG  chair_elevation
LOG  floor_to_stand
LOG  hand_to_knees
LOG  chair_elevation
LOG  squat
LOG  leg_lifts
LOG  rolling
LOG  toe_touches
LOG  toe_walking
LOG  step_up
LOG  step_up
LOG  step_up
LOG  step_up
LOG  step_up

Всякий раз, когда я бросаю туда console.info(comments), он показывает мне, что весь объект просто заполнен пустыми массивами. Самая запутанная часть заключается в том, что каждый массив имеет ровно 1 комментарий внутри него к концу процесса. Но я понятия не имею, как эти комментарии туда попали, потому что каждый раз, когда я записываю комментарии, в них нет ничего, кроме пустых массивов. Что дает???

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

pilchard 09.01.2023 23:37
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
1
61
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема

Проблема в том, что состояние comments, на которое неоднократно ссылаются, является закрытием устаревшего состояния по сравнению с начальным состоянием. Каждый цикл перезаписывает предыдущее обновление состояния очереди циклов.

useEffect(() => {
  let allComments = selectedClient.plan.comments
  for( let i = 0; i < selectedClient.plan.comments.length; i ++){
    let tag = allComments[i].videoId
    console.info(tag)
    if (comments[tag]) {              // <-- (1) stale closure over initial state
      let newArr = [...comments[tag]] // <-- (2) spreads empty array
      newArr.push(allComments[i])
      let newObj = { ...comments }    // <-- (3) shallow copy initial state object
      newObj[tag] = newArr
      setComments(comments => ({      // <-- (4) shallow copy copy of state
        ...newObj
      }))
    }
  }
  setLoading(false)
}, [selectedClient])

Последнее обновление состояния в очереди — это то, которое вы, наконец, увидите при повторном рендеринге компонента.

Решение

Предлагается использовать обновление функционального состояния для правильного обновления любого предыдущего состояния вместо использования того, что закрыто в области обратного вызова.

useEffect(() => {
  selectedClient.plan.comments.forEach(comment => {
    const { videoId } = comment;

    // Enqueue functional state update
    setComments(comments => {
      if (comments[videoId]) {
        // State has matching property value, update state
        return {
          ...comments,
          [videoId]: comments[videoId].concat(comment);
        };
      } else {
        // Nothing to update, return existing state
        return comments;
      }
    });
  });
  setLoading(false);
}, [selectedClient]);

Другие вопросы по теме