React'te setState ile bir nesneyi güncelleme

Nesnenin özelliklerini setState ile güncellemek mümkün müdür?

Şöyle bir şey:

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

Denedim:

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

ve bu:

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

İlki bir sözdizimi hatasıyla sonuçlanırken ikincisi hiçbir şey yapmaz. Fikri olan var mı?

Çözüm

Durum güncellemesi bir async işlemi olduğundan, bunu yapmanın birden fazla yolu vardır, bu nedenle durum nesnesini güncellemek için setState ile updater işlevi kullanmamız gerekir.

1- En basit olanı:

Önce jasperın bir kopyasını oluşturun, ardından değişiklikleri bu kopyada yapın:

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` kullanmak yerine bu şekilde de yazabiliriz:

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

2- [yayma operatörünü]3 kullanma:

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
    }
}))

Not: Object.assign ve Spread Operator yalnızca shallow copy oluşturur, bu nedenle iç içe nesne veya nesne dizisi tanımladıysanız, farklı bir yaklaşıma ihtiyacınız vardır.


İç içe geçmiş durum nesnesi güncelleniyor:

Durumu şu şekilde tanımladığınızı varsayalım:

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

Pizza nesnesinin extraCheese öğesini güncellemek için:

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
    }
  }
}))

Nesne dizisi güncelleniyor:

Bir yapılacaklar uygulamanız olduğunu ve bu formdaki verileri yönettiğinizi varsayalım:

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

Herhangi bir todo nesnesinin durumunu güncellemek için, dizi üzerinde bir harita çalıştırın ve her nesnenin bazı benzersiz değerlerini kontrol edin, condition=true durumunda, güncellenmiş değere sahip yeni nesneyi döndürün, aksi takdirde aynı nesneyi döndürün.

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

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

}))

Öneri: Nesnenin benzersiz bir değeri yoksa, dizi indeksi kullanın.

Yorumlar (11)

İlk durum gerçekten de bir sözdizimi hatasıdır.

Bileşeninizin geri kalanını göremediğim için, burada durumunuzdaki nesneleri neden iç içe yerleştirdiğinizi görmek zor. Bileşen durumundaki nesneleri iç içe yerleştirmek iyi bir fikir değildir. Başlangıç durumunuzu şu şekilde ayarlamayı deneyin:

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

Bu şekilde, adı güncellemek isterseniz, sadece arayabilirsiniz:

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

Bu, hedeflediğiniz şeye ulaşmanızı sağlayacak mı?

Daha büyük, daha karmaşık veri depoları için Redux gibi bir şey kullanırdım. Ama bu çok daha gelişmiş bir yöntem.

Bileşen durumu ile ilgili genel kural, bunu yalnızca bileşenin kullanıcı arayüzü durumunu yönetmek için kullanmaktır (örn. etkin, zamanlayıcılar, vb.)

Bu referanslara göz atın:

Yorumlar (2)

Başka bir seçenek: değişkeninizi Jasper nesnesi dışında tanımlayın ve sonra sadece bir değişkeni çağırın.

Yayılma operatörü: 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
    }
})
Yorumlar (1)