React JS useState Multi-level Data

У меня вопрос по поводу setState React.

Например, у меня есть эти данные

data_menus = [
  {
    id: 1,
    title: "Title",
    preview: '../img/',
    pages: [
      {
        id: 1,
        type: 'first page',
        background: '../img/',
        components: []
      },
      {
        id: 2,
        type: 'Second Page',
        background: '../img/',
        components: []
      }
    ],
  }
]

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

setCurrentState({
  ...currentState,
  pages: [{...currentState.pages[0], components:[...currentState.pages[0].components,{
    id: 1,
    type: '',
  }]}]
})

я пробую добавить

{
    id: 1,
    type: ''   
}

Нужно оставить все данные без изменения внести новые только в components[]

Вот так :

data_menus = [
  {
    id: 1,
    title: "Title",
    preview: '../img/',
    pages: [
      {
        id: 1,
        type: 'first page',
        background: '../img/',
        components: [
            0: { id:1 , type: ''}
        ]
      },
      {
        id: 2,
        type: 'Second Page',
        background: '../img/',
        components: [
            0: { id:1 , type: ''}
        ]
      }
    ],
  }
]

Подскажите, пожалуйста, как это сделать. Спасибо!


Ответы (1 шт):

Автор решения: Sire IMPACTUS
setCurrentState(previousState => {
    const clone = { ...previousState };
    clone.pages[0].components.push({
        id: 1,
        type: ''   
    });
    return clone;
});

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

PS: Почему-то useEffect не подключался, поэтому сделал через таймер.

let cancel = false;

function App() {
  const [state, setState] = React.useState([{
    id: 1,
    title: "Title",
    preview: '../img/',
    pages: [{
        id: 1,
        type: 'first page',
        background: '../img/',
        components: []
      },
      {
        id: 2,
        type: 'Second Page',
        background: '../img/',
        components: []
      }
    ],
  }])

  if (cancel === false) {
    setTimeout(() => {
      cancel = true;
      setState(previousState => {
        const clone = { ...previousState
        };
        clone[0].pages[0].components.push({
          id: 1,
          type: ''
        });
        return clone;
      });

    }, 3000)
  }


  console.log(state)
  return null
}
const domContainer = document.querySelector('#root');
const root = ReactDOM.createRoot(domContainer);
root.render( < App / > );
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<div id="root"></div>

→ Ссылка