React — useState — как частично обновить объект состояния

#javascript #reactjs #react-hooks #state

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

Вопрос:

Проблема

Привет,

Я пытаюсь частично обновить свой объект состояния :

 const [elephantProp, setElephantProp] = useState({
        name: "",
        color: "",
        size: "",
        race: "",
        country: "",
    });
  

Допустим, я хочу обновить только параметры цвета и размера.

Что я пробовал

1

Динамически изменять параметры (в соответствии с входным объектом) :

 const handleChange = (input) => {
    Object.keys(input).forEach((key) => {
        setElephantProp({ ...elephantProp, [key]: input[key] });
    };
  

Вывод: измените только последний параметр (размер).

2

Установите все параметры сразу :

 const handleChange = (input) => {
        setElephantProp({ ...elephantProp, color: input.color, size: input.size });
    };
  

Вывод: работает, но не является динамическим (если я добавлю параметр к входному объекту, эффектов не будет)

Есть ли у вас какие-либо идеи о том, как динамически обновлять некоторые из моих переменных состояния?

Может быть, мне следует рассмотреть возможность разделения на несколько переменных состояния (неудобно с большим количеством переменных) или использования вложенных объектов?

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

1. setElephantProp — это асинхронный метод, вот почему это происходит. Когда вы просматриваете его, вы не получаете обновленное значение состояния. итак, последнее значение обновляется. Не могли бы вы, пожалуйста, попробовать то же самое с циклом синхронизации, а forEach — асинхронный. Надеюсь, это поможет вам.

Ответ №1:

Из вашего кода я собираюсь предположить, что input это объект, представляющий обновления состояния, например

 {
    name: "Dumbo",
    country: "USA"
}
  

В этом случае вы можете просто сделать:

 const handleChange = (input) => {
    setElephantProp({ ...elephantProp, ...input });
}
  

Как ...input последнее, его свойства будут перезаписывать elephantProp свойства, которые имеют тот же ключ.
Пожалуйста, обратите внимание, что таким образом все input ключи, которых нет в elephantProp , будут добавлены в состояние; например

 const elephantProp = {
  name: "",
  color: "",
  size: "",
  race: "",
  country: "",
};

const input = {
  name: "Dumbo",
  country: "USA",
  ableToFly: true,
};

const updatedElephantProp = {
  ...elephantProp,
  ...input
} // => the updated state will contain the key/value pair 'ableToFly: true' too

console.log(updatedElephantProp)  

Такое поведение может быть желательным или нет, в зависимости от ваших потребностей и спецификаций проекта.

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

1. Спасибо! Это идеально соответствует моим потребностям, поскольку я контролирую то, что может быть сохранено во входном объекте. Теперь моя функция handleChange выглядит следующим образом: ` const handleChange = (input) => { setElephantProp({ … elephantProp, …ввод }); }; `

Ответ №2:

Вы можете использовать concept useReducer — обычно предпочтительнее useState, когда у вас сложная логика состояния, которая включает в себя несколько вложенных значений — useReducer

     const [changes, onChange] = useReducer((value, change) => ({...(value || {}), ...change}), {});

    //used
    const {name, color, size, race, country} = changes;
    
    const handleChange = change => {
        //example change = {name: 'alex'}
        onChange(change);
    };
  

Ответ №3:

React рекомендует использовать несколько состояний для разных переменных. Однако, если вы хотите установить полный объект, вы, скорее всего, предпочтете скопировать объект, и setState только один раз. Ваш цикл может быть неправильно пойман при повторном отображении, поскольку это асинхронная функция.

Я не уверен, какова ваша реализация, но что-то вроде этого должно работать:

 const handleChange = (objectIn) => {
  // create a new object merging the old one and your input
  const newElephant = {
    ...elephantProps,
    ...objectIn
  }
  setElephantProps(newElephant)
}
  

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

   const onChange = ({ target: { value, name } }) => setElephant({
    ...elephant,
    [name]: value
  })
  return <input onChange={onChange} name="size" value={elephant.size} />
  

Ответ №4:

Вы можете передать 2-й параметр в handleChange, например:

 const handleChange = (input, name) => {
    setElephantProp({ ...elephantProp, [name]: input[name] });
};
  

Ответ №5:

Одно из ваших решений здесь: codesandbox.io или приведенный ниже код, использующий этот подход.

   const onChangeHandaller = (e) => {
    setElephantProp({ ...elephantProp, [e.target.name]: e.target.value });
  };
  

введите описание изображения здесь

 const [elephantProp, setElephantProp] = useState({
    name: "",
    color: "",
    size: "",
    race: "",
    country: ""
  });

  const onChangeHandaller = (e) => {
    setElephantProp({ ...elephantProp, [e.target.name]: e.target.value });
  };

  return (
    <div className="App">
      Name:{" "}
      <input
        value={elephantProp.name}
        name="name"
        onChange={(e) => onChangeHandaller(e)}
      />{" "}
      <br />
      Color:{" "}
      <input
        value={elephantProp.color}
        name="color"
        onChange={(e) => onChangeHandaller(e)}
      />{" "}
      <br />
      Size:{" "}
      <input
        value={elephantProp.size}
        name="size"
        onChange={(e) => onChangeHandaller(e)}
      />{" "}
      <br />
      Race:{" "}
      <input
        value={elephantProp.race}
        name="race"
        onChange={(e) => onChangeHandaller(e)}
      />{" "}
      <br />
      Country:{" "}
      <input
        value={elephantProp.country}
        name="country"
        onChange={(e) => onChangeHandaller(e)}
      />{" "}
      <br />
    </div>