обновление состояния с помощью перехватов в массиве объектов

#javascript #reactjs #react-hooks #state

#javascript #reactjs #реагировать-перехваты #состояние

Вопрос:

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

 const [components, setComponents] = useState([
  {
    compName: "Weather",
    path: 'weather',
    active: false
  },
  {
    compName: "Tasks",
    path: 'tasks',
    active: false
  },
])
                                                      

 function onActivateHandler(){
      setComponents((prevComponents) => {
        const copy = [...prevComponents]
        let newState = {...copy[1]}
        newState.active = true
        console.log(newState)
    
        return  {...prevComponents}
      })
 }
  

Ответ №1:

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

Редактировать: сейчас выглядит не так красиво, но это безопасно.

 function onActivateHandler(){
    setComponents((prevComponents) => {
      const copy = [...s];
      const newState = {...copy.splice(1, 1)[0]}
      newState.active = true;
      return [...copy, newState];
    })
 }
  

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

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

2. Верно, я забыл, что вам придется это сращивать. Просто месяц.

Ответ №2:

Я думаю, что вам просто нужно сгенерировать новую ссылку для всего массива.

Еще одна вещь, которую я заметил, это то, что вы возвращаете объект из своей setComponents() функции. Поскольку переменная состояния components является массивом, я думаю, вам нужно вернуть массив.

Кроме того, напишите onActivateHandler() метод в виде функции со стрелкой, чтобы привязать его к контексту компонента, на всякий случай, обычно это то, что вы хотели бы сделать.

Я бы написал это так (я переключаю активное значение просто для демонстрации):

 const myComponent = () => {
    const [components, setComponents] = useState([
        {
           compName: "Weather",
           path: "weather",
           active: false,
        },
        {
           compName: "Tasks",
           path: "tasks",
           active: false,
        },
    ]);

    const onActivateHandler = () => {
        setComponents((prevComponents) => {
           // update the array reference
           const newState = [...prevComponents];
           newState[1].active = !newState[1].active;

           // Your state variable is an array,
           // so you need to return an array
           return [...prevComponents];
        });
    };

    return (
        <>
            <button onClick={onActivateHandler}>Click</button>
            <div>{components[1].active ? 'active' : 'inactive'}</div>
        </>
    )
};
  

Как lawrence-witt сказано ниже, отказ от создания нового объекта внутри нового массива в некоторых случаях может привести к отказу от повторного рендеринга, но в вашем простом случае приведенный выше код работает нормально, поскольку react отслеживает ссылку на массив, а не ссылку на объекты внутри. Вы можете распространить newState[1] на новый объект, если вам нужно, но вам нужно будет удалить старый из массива состояний.

Ваше здоровье!

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

1. Это не такая уж хорошая идея, потому что без клонирования объекта вы сохраните его ссылку и измените состояние перед его установкой. Это часто приводит к тому, что повторный запуск не запускается.

2. Нет, конечно, я в курсе этого. Я просто понимаю, что ссылка, отслеживаемая react, является ссылкой на массив. Но я могу ошибаться. Я протестирую его и отредактирую при необходимости.

3. Опасность здесь не только в том, что React не выполнит надлежащую проверку на равенство возвращаемого состояния и повторно отобразит этот компонент, но и в том, что любые подкомпоненты, которые принимают components[1].active в качестве prop, будут вести себя неожиданным образом, когда это значение будет преждевременно изменено. Я бы рекомендовал разделять ссылки при изменении любого состояния React.