Подтвердить что ты не робот

Обновление объекта с помощью setState в React

Возможно ли вообще обновить свойства объекта с помощью setState?

Что-то вроде:

this.state = {
   jasper: { name: 'jasper', age: 28 },
}

Я пытался:

this.setState({jasper.name: 'someOtherName'});

и это:

this.setState({jasper: {name: 'someothername'}})

Первое приводит к синтаксической ошибке, а второе просто ничего не делает. Есть идеи?

4b9b3361

Ответ 1

Есть несколько способов сделать это, так как обновление состояния является асинхронной операцией, поэтому для обновления объекта состояния нам нужно использовать функцию обновления с setState.

1- Самый простой:

Сначала создайте копию jasper затем внесите изменения в это:

this.setState(prevState => {
  let jasper = Object.assign({}, prevState.jasper);  // creating copy of state variable jasper
  jasper.name = 'someothername';                     // update the name property, assign a new value                 
  return { jasper };                                 // return new object jasper object
})

Вместо использования Object.assign мы также можем написать его так:

let jasper = { ...prevState.jasper };

2- Использование оператора распространения:

this.setState(prevState => ({
    jasper: {                   // object that we want to update
        ...prevState.jasper,    // keep all other key-value pairs
        name: 'something'       // update the value of specific key
    }
}))

Примечание: Object.assign и Spread Operator создают только поверхностную копию, поэтому, если вы определили вложенный объект или массив объектов, вам нужен другой подход.


Обновление вложенного объекта состояния:

Предположим, вы определили состояние как:

this.state = {
  food: {
    sandwich: {
      capsicum: true,
      crackers: true,
      mayonnaise: true
    },
    pizza: {
      jalapeno: true,
      extraCheese: false
    }
  }
}

Чтобы обновить объект extraCheese of pizza:

this.setState(prevState => ({
  food: {
    ...prevState.food,           // copy all other key-value pairs of food object
    pizza: {                     // specific object of food object
      ...prevState.food.pizza,   // copy all pizza key-value pairs
      extraCheese: true          // update value of specific key
    }
  }
}))

Обновление массива объектов:

Предположим, у вас есть приложение todo, и вы управляете данными в этой форме:

this.state = {
  todoItems: [
    {
      name: 'Learn React Basics',
      status: 'pending'
    }, {
      name: 'Check Codebase',
      status: 'pending'
    }
  ]
}

Чтобы обновить состояние любого объекта todo, запустите карту в массиве и проверьте наличие уникального значения каждого объекта, в случае condition=true верните новый объект с обновленным значением, в противном случае - тот же объект.

let key = 2;
this.setState(prevState => ({

  todoItems: prevState.todoItems.map(
    el => el.key === key? { ...el, status: 'done' }: el
  )

}))

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

Ответ 2

Это самый быстрый и самый читаемый способ:

this.setState({...this.state.jasper, name: 'someothername'});

Даже если this.state.jasper уже содержит свойство name, будет использоваться новое имя name: 'someothername'.

Ответ 3

Используйте оператор распространения и немного ES6 здесь

this.setState({
    jasper: {
          ...this.state.jasper,
          name: 'something'
    }
})

Ответ 4

Я использовал это решение.

Если у вас есть вложенное состояние, подобное этому:

this.state = {
  formInputs:{
    friendName:{
      value:'',
      isValid:false,
      errorMsg:''
    },
    friendEmail:{
      value:'',
      isValid:false,
      errorMsg:''
    }
  }
}

вы можете объявить функцию handleChange, которая копирует текущий статус и переназначает его с измененными значениями

handleChange(el) {
    let inputName = el.target.name;
    let inputValue = el.target.value;

    let statusCopy = Object.assign({}, this.state);
    statusCopy.formInputs[inputName].value = inputValue;

    this.setState(statusCopy);
  }

здесь HTML с прослушивателем событий. Убедитесь, что вы используете то же имя, что и для объекта состояния (в нашем случае это FriendName)

<input type="text" onChange={this.handleChange} " name="friendName" />

Ответ 5

попробуйте это, оно должно работать нормально

this.setState(Object.assign(this.state.jasper,{name:'someOtherName'}));

Ответ 6

Первый случай - действительно синтаксическая ошибка.

Так как я не вижу остальных компонентов, трудно понять, почему вы размещаете объекты в своем состоянии здесь. Неплохо встраивать объекты в состояние компонента. Попробуйте установить начальное состояние:

this.state = {
  name: 'jasper',
  age: 28
}

Таким образом, если вы хотите обновить имя, вы можете просто вызвать:

this.setState({
  name: 'Sean'
});

Достигнет ли это того, к чему вы стремитесь?

Для больших, более сложных хранилищ данных я бы использовал что-то вроде Redux. Но это гораздо более продвинутый.

Общее правило с состоянием компонента - использовать его только для управления состоянием пользовательского интерфейса компонента (например, активным, таймерам и т.д.).

Проверьте эти ссылки:

Ответ 7

Другой вариант: определить вашу переменную из объекта Jasper, а затем просто вызвать переменную.

Оператор спреда: ES6

this.state = {  jasper: { name: 'jasper', age: 28 } } 

let foo = "something that needs to be saved into state" 

this.setState(prevState => ({
    jasper: {
        ...jasper.entity,
        foo
    }
})

Ответ 8

Также, следуя решению Альберто Пираса, если вы не хотите копировать весь объект "состояние":

handleChange(el) {
    let inputName = el.target.name;
    let inputValue = el.target.value;

    let jasperCopy = Object.assign({}, this.state.jasper);
    jasperCopy[inputName].name = inputValue;

    this.setState({jasper: jasperCopy});
  }

Ответ 9

Вы можете попробовать это:

this.setState(prevState => {
   prevState = JSON.parse(JSON.stringify(this.state.jasper));
   prevState.name = 'someOtherName';
   return {jasper: prevState}
})

или для другого имущества:

this.setState(prevState => {
   prevState = JSON.parse(JSON.stringify(this.state.jasper));
   prevState.age = 'someOtherAge';
   return {jasper: prevState}
})

Или вы можете использовать функцию handleChage:

handleChage(event) {
   const {name, value} = event.target;
    this.setState(prevState => {
       prevState = JSON.parse(JSON.stringify(this.state.jasper));
       prevState[name] = value;
       return {jasper: prevState}
    })
}

и HTML-код:

<input 
   type={"text"} 
   name={"name"} 
   value={this.state.jasper.name} 
   onChange={this.handleChange}
/>
<br/>
<input 
   type={"text"} 
   name={"age"} 
   value={this.state.jasper.age} 
   onChange={this.handleChange}
/>

Ответ 10

Вы можете попробовать это:  (Примечание: имя входного тега === поле объекта)

<input name="myField" type="text" 
      value={this.state.myObject.myField} 
     onChange={this.handleChangeInpForm}>
</input>

-----------------------------------------------------------
handleChangeInpForm = (e) => {
   let newObject = this.state.myObject;
   newObject[e.target.name] = e.target.value;
   this.setState({
     myObject: newObject 
   })
}

Ответ 11

Простой и динамичный способ.

Это сделает работу, но вам нужно установить все идентификаторы для родителя, чтобы родитель указывал на имя объекта, то есть id = "jasper" и называл имя свойства input element = свойство внутри объекта jasper.,

handleChangeObj = ({target: { id , name , value}}) => this.setState({ [id]: { ...this.state[id] , [name]: value } });

Ответ 12

Без использования Async и Await Используйте это...

funCall(){    
     this.setState({...this.state.jasper, name: 'someothername'});
}

Если вы используете с Async и Await, используйте это...

async funCall(){
      await this.setState({...this.state.jasper, name: 'someothername'});
}

Ответ 13

Это моя функция handleInputChange. Он работает в общем виде для любого типа объекта. Тем не менее

Использование Eval настоятельно не рекомендуется

handleInputChange(event) {
  const target = event.target;

  const targetPropertyName = target.name.substr(target.name.indexOf('.'));
  const targetObjectName = target.name.substr(0, target.name.indexOf('.'));
  const value = target.value;

  var obj = this.state[targetObjectName];

  eval('obj' + targetPropertyName + '= value');

  this.setState({
    [targetObjectName]: obj
  });
}

И это моя форма ввода

<input id="inputEmail" type="email" value={this.state.user.email} name="user.email" onChange={this.handleInputChange}/>

Любые идеи, чтобы заменить функцию Eval?

Ответ 14

это еще одно решение, использующее immer утилиту immutabe, очень легко подходящее для глубоко вложенных объектов, и вам не следует беспокоиться о мутации

this.setState(
    produce(draft => {
       draft.jasper.name = 'someothername
    })
)