React'te iç içe durum özellikleri nasıl güncelleştirilir


390

Böyle iç içe özelliği kullanarak durumumu düzenlemeye çalışıyorum:

this.state = {
   someProperty: {
      flag:true
   }
}

Ancak durumu bu şekilde güncellemek,

this.setState({ someProperty.flag: false });

çalışmıyor. Bu nasıl doğru şekilde yapılabilir?


4
Ne demek çalışmıyor? Bu çok iyi bir soru değil - ne oldu? Herhangi bir hata var mı? Ne hataları?
Darren Sweeney


16
Cevap Tepki'de Yuvalanmış Durumu Kullanma . Bu mükemmel cevabı okuyun .
Qwerty

4
Bunun yerine ne kullanılmalı?
Jānis Elmeris

42
Sadece iç içe durumu kullanmamak, React'ın ne kadar yaygın olarak kullanıldığı için kabul edilemez bir cevaptır. Bu durum ortaya çıkacak ve geliştiricilerin buna cevap vermeleri gerekiyor.
serraosays

Yanıtlar:


455

İçin setStateben setState iç içe güncelleştirmeleri işlemez düşünüyorum iç içe geçmiş bir nesne için size yaklaşımı aşağıda takip edebilirsiniz.

var someProperty = {...this.state.someProperty}
someProperty.flag = true;
this.setState({someProperty})

Fikir, kukla bir nesne üzerinde işlemler gerçekleştirmek ve ardından bileşenin durumunu güncellenen nesneyle değiştirmek

Şimdi, yayma işleci nesnenin yalnızca bir düzey iç içe kopyasını oluşturur. Durumunuz aşağıdaki gibi iç içe geçmişse:

this.state = {
   someProperty: {
      someOtherProperty: {
          anotherProperty: {
             flag: true
          }
          ..
      }
      ...
   }
   ...
}

Gibi her düzeydeki forma operatörünü kullanarak

this.setState(prevState => ({
    ...prevState,
    someProperty: {
        ...prevState.someProperty,
        someOtherProperty: {
            ...prevState.someProperty.someOtherProperty, 
            anotherProperty: {
               ...prevState.someProperty.someOtherProperty.anotherProperty,
               flag: false
            }
        }
    }
}))

Ancak yukarıdaki sözdizimi, durum gittikçe daha fazla iç içe geçtikçe her çirkinleşiyor ve bu nedenle immutability-helperdurumu güncellemek için paket kullanmanızı öneririz .

Durumun nasıl güncelleneceği ile ilgili bu cevaba bakınız immutability helper.


2
@Ohgodwhy, hayır bu {... this.state.someProperty} yeni bir obejct'e geri döndüğü için doğrudan devlete erişmiyor somePropertyve biz bunu değiştiriyoruz
Shubham

4
Bu benim için işe yaramadı .. 15.6.1 @ tepki sürümünü kullanıyorum
Rajiv

5
@Stophface Lodash'ı derin klonlamak için kullanabiliriz, ancak herkes bu kütüphaneyi sadece setState'e dahil etmeyecek
Shubham

15
Bu reaktjs.org/docs/… 'ı ihlal etmiyor mu? Yuvalanmış nesnede iki değişiklik toplu hale getirilirse, son değişiklik birincinin üzerine yazılır. Yani en doğru yol şu olurdu: this.setState((prevState) => ({nested: {...prevState.nested, propertyToSet: newValue}}) Yine de biraz sıkıcı ...
olejorgenb

2
...prevState,Son örnekte ihtiyacın olduğunu sanmıyorum , sadece sen somePropertyve çocukları
Jemar Jones

140

Bir satıra yazmak için

this.setState({ someProperty: { ...this.state.someProperty, flag: false} });

12
SetState içinde buna doğrudan erişmek yerine setState için güncelleyicinin kullanılması önerilir. reaktjs.org/docs/react-component.html#setstate
Raghu Teja

6
İnanıyorum ki, this.statehemen sonra okuma setStateve yeni bir değere sahip olmasını beklemeyin. Çağırmadan Karşı this.stateiçinde setState. Ya da ikincisinde benim için net olmayan bir sorun mu var?
trpt4him

2
Gibi trpt4him dedi, bu bağlantı yalnızca ulaşma sorun hakkında görüşmeler verdi this.statesonra setState. Ayrıca, biz geçmezken this.stateiçin setState. Operatör yayılmış özellikleri. Object.assign () ile aynıdır. github.com/tc39/proposal-object-rest-spread
Yoseph

3
@RaghuTeja belki sadece this.setState(currentState => { someProperty: { ...currentState.someProperty, flag: false} });bu sorunu önlemek için izin verebilir?
Webwoman

Ben eksiksizlik için useState kanca ile aynı elde nasıl cevap ekledim .
Andrew

90

Bazen doğrudan cevaplar en iyisi değildir :)

Kısa versiyon:

bu kod

this.state = {
    someProperty: {
        flag: true
    }
}

gibi bir şey basitleştirilmelidir

this.state = {
    somePropertyFlag: true
}

Uzun versiyon:

Şu anda React'te iç içe durumla çalışmak istememelisiniz . React, iç içe geçmiş durumlarla çalışmaya yönelik olmadığından ve burada önerilen tüm çözümlerin kesmek gibi göründüğünden. Çerçeveyi kullanmazlar, onunla savaşırlar. Bazı özellikleri gruplamak için şüpheli bir amaç için çok açık olmayan bir kod yazmayı önerirler. Bu yüzden meydan okumaya bir cevap olarak çok ilginçler, ancak pratik olarak işe yaramazlar.

Aşağıdaki durumu düşünelim:

{
    parent: {
        child1: 'value 1',
        child2: 'value 2',
        ...
        child100: 'value 100'
    }
}

Yalnızca değerini değiştirirseniz ne olur child1? React, sığ karşılaştırmayı kullandığından ve parentmülkün değişmediğini göreceğinden görünümü yeniden oluşturmaz . Durum nesnesini doğrudan değiştiren BTW genel olarak kötü bir uygulama olarak kabul edilir.

Bu yüzden bütünü yeniden oluşturmanız gerekir parent nesneyi . Ancak bu durumda başka bir sorunla karşılaşacağız. Tepki tüm çocukların değerlerini değiştirdiğini ve hepsini yeniden yaratacağını düşünecektir. Elbette performans için iyi değil.

Bu sorunu bazı karmaşık mantık yazarak çözmek hala mümkündür, shouldComponentUpdate()ancak burada durmayı ve kısa versiyondan basit bir çözüm kullanmayı tercih ederim.


4
Bence iç içe geçmiş durumun gayet iyi olduğu kullanım durumları var. Örneğin, anahtar / değer çiftlerini dinamik olarak takip eden bir durum. Buraya, eyaletteki tek bir giriş için durumu nasıl güncelleyebileceğinize bakın: reaktjs.org/docs/…
pors

1
Sığ karşılaştırma varsayılan olarak saf bileşenler için kullanılır.
Basel Shishani

4
Onuruna bir sunak yaratmak ve her sabah ona dua etmek istiyorum. OBVIOUS tasarım kararını mükemmel bir şekilde açıklayan bu cevaba ulaşmak üç günümü aldı. Herkes sadece yayılma operatörünü kullanmaya veya iç içe geçmiş daha insan tarafından okunabilir göründüğü için başka kesmek yapmaya çalışır.
Edeph

1
Öyleyse, etkileşimli bir ağaç oluşturmak gibi şeyler yapmak için React'i kullanmayı nasıl önerirsiniz (örneğin, şirketim dünyanın farklı bölgelerinde, her biri farklı türde, farklı özelliklerde, farklı konumlarda (80+) bir grup sensöre sahiptir. ) ve DERSİNDEN, her dağıtım binlerce dolara mal olduğu ve tam bir proje olduğu için bir hiyerarşi içinde organize edilirler, bu nedenle bunları hiyerarşi olmadan yönetmek imkansız olacaktır). React'ta ağaçlar gibi ... ağaçlar gibi şeyleri nasıl modellemeyeceğinizi merak ediyorum.
DanyAlejandro

10
React önemsiz olmayan derinliklerin özyinelemeli bir yapısı olarak saklanan hiçbir şeyi temsil etmek için yapılmamış gibi görünüyor. Ağaç görünümleri hemen hemen her karmaşık uygulamada (gmail, dosya yöneticileri, herhangi bir belge yönetim sistemi, ...) göründüğü için biraz hayal kırıklığı yaratıyor. Bu şeyler için React kullandım, ancak her zaman herkese anti-desen yaptığınızı söyleyen ve çözümün ağacın derin kopyalarını her düğümün durumunda tuttuğunu (evet, 80 kopya) olduğunu gösteren bir React zealotı vardı. Herhangi bir React kuralını çiğnemeyen, hacky olmayan ağaç görünümü bileşeni görmek isterim.
DanyAlejandro

61

feragat

Tepki'deki Yuvalanmış Durum yanlış tasarım

Bu mükemmel cevabı okuyun .

 

Bu cevabın arkasında yatan akıl yürütme:

React's setState sadece yerleşik bir kolaylıktır, ancak yakında sınırlarının olduğunu fark edersiniz. Özel özellikleri kullanmak ve forceUpdate'in akıllı kullanımı size çok daha fazlasını sunar. Örneğin:

class MyClass extends React.Component {
    myState = someObject
    inputValue = 42
...

Örneğin MobX, durumu tamamen terk eder ve özel gözlemlenebilir özellikler kullanır.
React bileşenlerinde durum yerine Gözlenebilirler kullanın.

 


sefaletin cevabı - buradaki örneğe bakın

İç içe yerleştirilmiş her özelliği güncellemenin başka bir kısa yolu daha vardır .

this.setState(state => {
  state.nested.flag = false
  state.another.deep.prop = true
  return state
})

Bir satırda

 this.setState(state => (state.nested.flag = false, state))

not: Bu, Virgül operatörü ~ MDN , burada çalışırken bakın (Korumalı Alan) .

Buna benzer (bu durum durum referansını değiştirmez)

this.state.nested.flag = false
this.forceUpdate()

Bu bağlamdaki forceUpdateve arasındaki ince fark içinsetState bağlanmış örneğe bakın.

Tabii ki bu, statesalt okunur olması gerektiği gibi bazı temel ilkeleri kötüye kullanıyor , ancak eski durumu hemen atıp yeni durumla değiştirdiğiniz için, tamamen tamam.

Uyarı

Hatta devlet içeren bileşen olsa edecektir güncelleyip rerender düzgün ( bu Yakaladım hariç ) , sahne olacaktır başarısız çocuklara yaymak için (aşağıda Mossad başının yorumunu bakınız) . Bu tekniği sadece ne yaptığınızı biliyorsanız kullanın.

Örneğin, kolayca güncellenen ve iletilen değiştirilmiş düz bir pervane geçirebilirsiniz.

render(
  //some complex render with your nested state
  <ChildComponent complexNestedProp={this.state.nested} pleaseRerender={Math.random()}/>
)

Artık complexNestedProp referansı değişmese de ( shouldComponentUpdate )

this.props.complexNestedProp === nextProps.complexNestedProp

bileşen , üst bileşen her güncelleştirildiğinde yeniden gönderilir; bu, çağrıldıktan sonra this.setStateveya üst öğe için geçerlidir this.forceUpdate.

Devleti mutasyona uğratmanın etkileri

Kullanılması iç içe durumu farklı nesneler (bilinçli veya bilinçsiz) tutmak için farklı (daha eski) referanslar olabilir çünkü ve devleti doğrudan mutasyona tehlikelidir devlet ve ne zaman güncelleme mutlaka bilmiyor olabilir (örneğin kullanırken PureComponentveya eğer shouldComponentUpdategeri dönüşü uygulanmaktadır false) YA vardır aşağıdaki örnekteki gibi eski verileri görüntülemeye yöneliktir.

Geçmiş verileri oluşturması beklenen bir zaman çizelgesini hayal edin, verileri el altında mutasyona uğratmak, önceki öğeleri de değiştireceğinden beklenmedik davranışlarla sonuçlanacaktır.

Devlet akışlı devlet akış iç içe

Her neyse, burada Nested PureChildClassyayılmayan sahne nedeniyle yeniden gönderilmediğini görebilirsiniz .


12
Hiçbir yerde herhangi bir reaksiyon durumunu mutasyona uğratmamalısınız. State.nested veya state.another öğelerinden veri kullanan iç içe geçmiş bileşenler varsa, bunları yeniden oluşturmaz veya çocuklarını kullanmaz. Bunun nedeni, nesnenin değişmediği için React hiçbir şeyin değişmediğini düşünür.
Zeragamba

@ SpyMaster356 Buna cevap vermek için cevabımı güncelledim. Ayrıca MobX'in statetamamen hendeklediğini ve özel gözlemlenebilir özellikler kullandığını unutmayın . React's setStatesadece yerleşik bir kolaylıktır, ancak yakında sınırlarının olduğunu fark edersiniz. Özel özellikleri ve akıllı kullanımı forceUpdatesize çok daha fazlasını sunar. React bileşenlerinde durum yerine Gözlenebilirler kullanın.
Qwerty

Ayrıca bir örnek reakt-experiments.herokuapp.com/state-flow ekledim (üstteki git bağlantısı)
Qwerty

Örneğin, veritabanından iç içe nitelikleri olan bir nesneyi duruma yüklerseniz ne olur? Bu durumda yuvalanmış durumdan nasıl kaçınılır?
tobiv

3
@tobiv Bir getirme üzerine verileri farklı bir yapıya dönüştürmek daha iyidir, ancak bu kullanım alanına bağlıdır. Bazı verilerin kompakt birimleri olduğunu düşünüyorsanız, iç içe geçmiş bir nesnenin veya bir durum nesnesinin dizisinde olması sorun yaratmaz . Sorun, dahili React difing algoritmalarını doğru bir şekilde tetiklemek için düz olması gerektiğinden UI anahtarlarını veya diğer gözlemlenebilir verileri (yani, görünümü hemen değiştirmesi gereken veriler) depolamanız gerektiğinde ortaya çıkar. Diğer iç içe nesnelerdeki değişiklikler için, this.forceUpdate()belirli tetiklemek veya uygulamak kolaydır shouldComponentUpdate.
Qwerty

21

ES2015 kullanıyorsanız, Object.assign öğesine erişebilirsiniz. Yuvalanmış bir nesneyi güncellemek için bunu aşağıdaki gibi kullanabilirsiniz.

this.setState({
  someProperty: Object.assign({}, this.state.someProperty, {flag: false})
});

Güncellenen özellikleri var olanla birleştirir ve durumu güncellemek için döndürülen nesneyi kullanırsınız.

Düzenleme: Durumun doğrudan işaretleyicinin işaret ettiği gibi mutasyona uğratılmadığından emin olmak için atama işlevine hedef olarak boş bir nesne eklendi.


12
Ve yanılıyor olabilirim ama ES2015 olmadan React kullandığınızı sanmıyorum.
Madbreaks

16
const newState = Object.assign({}, this.state);
newState.property.nestedProperty = "new value";
this.setState(newState);

1
burada daha şık bir çözüm gibi görünüyor, 1) setState'in içindeki sıkıcı yayılmadan kaçınmak ve 2) setState'in içine doğrudan mutasyon yapmaktan kaçınarak yeni durumu setState'in içine güzelce koymak. Son fakat en az değil 3) sadece basit bir görev için herhangi bir kütüphane kullanımından kaçınmak
Webwoman

İki örnek eşdeğer değildir. Eğer propertybirkaç yuvalanmış özelliklerini içeren, onları ilk silecektir, ikinci olmaz. codesandbox.io/s/nameless-pine-42thu
Qwerty

Qwerty, haklısın, çaba için teşekkürler. ES6 sürümünü kaldırdım.
eyecandy.dev

Sağlam ve basit!
Tony Sepia

Çözümünüzü kullandım. Devlet hedefim küçük ve iyi çalıştı. React yalnızca değişen durum için mi render edecek yoksa her şeyi mi render edecek?
Kenji Noguchi

14

Buna yardımcı olacak birçok kütüphane var. Örneğin, değişmezlik yardımcısını kullanarak :

import update from 'immutability-helper';

const newState = update(this.state, {
  someProperty: {flag: {$set: false}},
};
this.setState(newState);

Lodash / fp setini kullanarak :

import {set} from 'lodash/fp';

const newState = set(["someProperty", "flag"], false, this.state);

Lodash / fp birleştirmeyi kullanma :

import {merge} from 'lodash/fp';

const newState = merge(this.state, {
  someProperty: {flag: false},
});

Kullanırsanız lodash, büyük olasılıkla _.cloneDeepdurumu klonlanmış kopya olacak şekilde denemek ve ayarlamak istersiniz .
Yixing Liu

@YixingLiu: Kullanımın cevabını güncelledim lodash/fp, bu yüzden mutasyonlar hakkında endişelenmemize gerek yok.
tokland

Sözdiziminin yanı sıra, lodash / fp işlevini seçmenin mergeveya setişlevlerin herhangi bir avantajı var mı?
Toivo Säwén

İyi cevap, belki this.setState(newState)de lodash / fp yöntemlerini çağırmanız gerektiğini eklemek istersiniz . Başka bir sorun da, lodash'ın .set(fp olmayan) beni bir süreliğine tetikleyen farklı bir argüman sırasına sahip olmasıdır.
Toivo Säwén

7

Bu tür sorunları çözmek için Immer https://github.com/mweststrate/immer kullanıyoruz .

Bu kodu bileşenlerimizden birinde değiştirdik

this.setState(prevState => ({
   ...prevState,
        preferences: {
            ...prevState.preferences,
            [key]: newValue
        }
}));

Bununla

import produce from 'immer';

this.setState(produce(draft => {
    draft.preferences[key] = newValue;
}));

İmmer ile durumunuzu "normal bir nesne" olarak ele alırsınız. Sihir, vekil nesnelerle sahnenin arkasında gerçekleşir.


6

İşte bu konudaki ilk cevapta fazladan paket, kitaplık veya özel işlev gerektirmeyen bir varyasyon.

state = {
  someProperty: {
    flag: 'string'
  }
}

handleChange = (value) => {
  const newState = {...this.state.someProperty, flag: value}
  this.setState({ someProperty: newState })
}

Belirli bir iç içe alanın durumunu ayarlamak için tüm nesneyi ayarladınız. Bunu bir değişken oluşturarak newStateve ilk önce ES2015 yayılma operatörünü kullanarak mevcut durumun içeriğini ona yayarak yaptım . Sonra, değerini this.state.flagyeni değerle değiştirdim ( geçerli durumu nesneye yaydıktan flag: value sonra ayarladığım için flag, geçerli durumdaki alan geçersiz kılınır). Sonra, ben sadece durumunu ayarlamak somePropertybenim için newStatenesne.


6

Yuvalama, bileşen durumuna gerçekten nasıl davranmanız gerektiği konusunda olmasa da, bazen tek katmanlı yuvalama için kolay bir şeydir.

Böyle bir devlet için

state = {
 contact: {
  phone: '888-888-8888',
  email: 'test@test.com'
 }
 address: {
  street:''
 },
 occupation: {
 }
}

Kullandığım yeniden kullanılabilir bir yöntem şöyle görünecektir.

handleChange = (obj) => e => {
  let x = this.state[obj];
  x[e.target.name] = e.target.value;
  this.setState({ [obj]: x });
};

sonra sadece adreslemek istediğiniz her yuvalama için obj adını girerek ...

<TextField
 name="street"
 onChange={handleChange('address')}
 />

4

Bu çözümü kullandım.

Böyle bir yuvalanmış durumunuz varsa:

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

geçerli durumu kopyalayan ve değiştirilen değerlerle yeniden atayan handleChange işlevini bildirebilirsiniz

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

olay dinleyicisiyle birlikte html

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

Onaylanmış. Zaten iç içe geçmiş özelliklere sahip önceden kurulmuş bir projeyle uğraşıyorsanız bu işe yarar.
metal_jacke1

4

Durumun bir kopyasını oluşturun:

let someProperty = JSON.parse(JSON.stringify(this.state.someProperty))

bu nesnede değişiklik yap:

someProperty.flag = "false"

şimdi durumu güncelleyin

this.setState({someProperty})

setState eşzamansızdır. Bu yüzden güncellenirken, başka biri bu işlevi çağırabilir ve durumun eski bir sürümünü kopyalayabilir.
Aviv Ben Shabat

3

Sınıf tabanlı bir React bileşeninin durumunu sormanıza rağmen, useState kancasında da aynı sorun vardır. Daha da kötüsü: useState kancası kısmi güncellemeleri kabul etmez. Bu nedenle, useState kancası kullanıldığında bu soru çok alakalı hale geldi.

Sorunun useState kancasının kullanıldığı daha modern senaryoları kapsadığından emin olmak için aşağıdaki cevabı göndermeye karar verdim:

Eğer varsa:

const [state, setState] = useState({ someProperty: { flag: true, otherNestedProp: 1 }, otherProp: 2 })

akımı klonlayarak ve verilerin gerekli segmentlerini yatırarak yuvalanmış özelliği ayarlayabilirsiniz, örneğin:

setState(current => { ...current, someProperty: { ...current.someProperty, flag: false } });

Ya da nesnenin klonlanmasını ve yamasını basitleştirmek için Immer kütüphanesini kullanabilirsiniz.

Veya sadece karmaşık (yerel ve küresel) durum verilerinin tamamen yönetimini ve performansı iyileştirmek için Hookstate kütüphanesini (sorumluluk reddi: Ben bir yazarım) kullanabilirsiniz:

import { useStateLink } from '@hookstate/core' 
const state = useStateLink({ someProperty: { flag: true, otherNestedProp: 1 }, otherProp: 2 })

oluşturulacak alanı al:

state.nested.someProperty.nested.flag.get()
// or 
state.get().someProperty.flag

yuvalanmış alanı ayarlayın:

state.nested.someProperty.nested.flag.set(false)

İşte durum, ağaç benzeri veri yapısında derin / özyinelemeli olarak iç içe yerleştirilmiş olan Hookstate örneği .


2

Henüz belirtilmeyen diğer iki seçenek:

  1. Derin iç içe geçmiş durumunuz varsa, alt nesneleri kökte oturacak şekilde yeniden yapılandırabileceğinizi düşünün. Bu, verilerin güncellenmesini kolaylaştırır.
  2. Redux belgelerinde listelenen değişmez durumu işlemek için birçok kullanışlı kütüphane bulunmaktadır . Immer'ı kod yazmanıza izin verdiğinden, ancak sahne arkasındaki gerekli klonlamayı işlediğinden Immer'i öneriyorum. Ayrıca, ortaya çıkan nesneyi dondurur, böylece daha sonra yanlışlıkla değiştiremezsiniz.

2

İşleri genel yapmak için @ ShubhamKhatri ve @ Qwerty'nin cevapları üzerinde çalıştım.

durum nesnesi

this.state = {
  name: '',
  grandParent: {
    parent1: {
      child: ''
    },
    parent2: {
      child: ''
    }
  }
};

giriş kontrolleri

<input
  value={this.state.name}
  onChange={this.updateState}
  type="text"
  name="name"
/>
<input
  value={this.state.grandParent.parent1.child}
  onChange={this.updateState}
  type="text"
  name="grandParent.parent1.child"
/>
<input
  value={this.state.grandParent.parent2.child}
  onChange={this.updateState}
  type="text"
  name="grandParent.parent2.child"
/>

updateState yöntemi

@ ShubhamKhatri'nin cevabı olarak setState

updateState(event) {
  const path = event.target.name.split('.');
  const depth = path.length;
  const oldstate = this.state;
  const newstate = { ...oldstate };
  let newStateLevel = newstate;
  let oldStateLevel = oldstate;

  for (let i = 0; i < depth; i += 1) {
    if (i === depth - 1) {
      newStateLevel[path[i]] = event.target.value;
    } else {
      newStateLevel[path[i]] = { ...oldStateLevel[path[i]] };
      oldStateLevel = oldStateLevel[path[i]];
      newStateLevel = newStateLevel[path[i]];
    }
  }
  this.setState(newstate);
}

@ Qwerty'nin cevabı olarak setState

updateState(event) {
  const path = event.target.name.split('.');
  const depth = path.length;
  const state = { ...this.state };
  let ref = state;
  for (let i = 0; i < depth; i += 1) {
    if (i === depth - 1) {
      ref[path[i]] = event.target.value;
    } else {
      ref = ref[path[i]];
    }
  }
  this.setState(state);
}

Not: Yukarıdaki yöntemler diziler için çalışmaz


2

Bileşen durumunuzun tam bir kopyasını oluşturma konusunda dile getirilen endişeleri çok ciddiye alıyorum . Bununla birlikte, Immer'i şiddetle öneririm .

import produce from 'immer';

<Input
  value={this.state.form.username}
  onChange={e => produce(this.state, s => { s.form.username = e.target.value }) } />

Bu, keyfi olarak derin bir durum ağacını verimli bir şekilde kopyalamak için akıllıca bir proxy nesnesi kullandığından ( React.PureComponentReact ile sığ durum karşılaştırmaları) için çalışmalıdır Immer. Immer, Immutability Helper gibi kütüphanelere kıyasla daha tipiktir ve Javascript ve Typcript kullanıcıları için idealdir.


Patlama yardımcı programı işlevi

function setStateDeep<S>(comp: React.Component<any, S, any>, fn: (s: 
Draft<Readonly<S>>) => any) {
  comp.setState(produce(comp.state, s => { fn(s); }))
}

onChange={e => setStateDeep(this, s => s.form.username = e.target.value)}

1
stateUpdate = () => {
    let obj = this.state;
    if(this.props.v12_data.values.email) {
      obj.obj_v12.Customer.EmailAddress = this.props.v12_data.values.email
    }
    this.setState(obj)
}

1
Bunun doğru olduğunu düşünmüyorum, çünkü objsadece devlete bir referans, bu yüzden gerçek this.statenesneyi mutasyona
uğratıyorsunuz

0

Bunun benim için işe yaradığını gördüm, örneğin bir kimliğin ve bir adın olduğu bir proje formuna sahiptim ve iç içe bir projenin durumunu sürdürmeyi tercih ederim.

return (
  <div>
      <h2>Project Details</h2>
      <form>
        <Input label="ID" group type="number" value={this.state.project.id} onChange={(event) => this.setState({ project: {...this.state.project, id: event.target.value}})} />
        <Input label="Name" group type="text" value={this.state.project.name} onChange={(event) => this.setState({ project: {...this.state.project, name: event.target.value}})} />
      </form> 
  </div>
)

Bilmeme izin ver!


0

Böyle bir şey yeterli olabilir,

const isObject = (thing) => {
    if(thing && 
        typeof thing === 'object' &&
        typeof thing !== null
        && !(Array.isArray(thing))
    ){
        return true;
    }
    return false;
}

/*
  Call with an array containing the path to the property you want to access
  And the current component/redux state.

  For example if we want to update `hello` within the following obj
  const obj = {
     somePrimitive:false,
     someNestedObj:{
        hello:1
     }
  }

  we would do :
  //clone the object
  const cloned = clone(['someNestedObj','hello'],obj)
  //Set the new value
  cloned.someNestedObj.hello = 5;

*/
const clone = (arr, state) => {
    let clonedObj = {...state}
    const originalObj = clonedObj;
    arr.forEach(property => {
        if(!(property in clonedObj)){
            throw new Error('State missing property')
        }

        if(isObject(clonedObj[property])){
            clonedObj[property] = {...originalObj[property]};
            clonedObj = clonedObj[property];
        }
    })
    return originalObj;
}

const nestedObj = {
    someProperty:true,
    someNestedObj:{
        someOtherProperty:true
    }
}

const clonedObj = clone(['someProperty'], nestedObj);
console.log(clonedObj === nestedObj) //returns false
console.log(clonedObj.someProperty === nestedObj.someProperty) //returns true
console.log(clonedObj.someNestedObj === nestedObj.someNestedObj) //returns true

console.log()
const clonedObj2 = clone(['someProperty','someNestedObj','someOtherProperty'], nestedObj);
console.log(clonedObj2 === nestedObj) // returns false
console.log(clonedObj2.someNestedObj === nestedObj.someNestedObj) //returns false
//returns true (doesn't attempt to clone because its primitive type)
console.log(clonedObj2.someNestedObj.someOtherProperty === nestedObj.someNestedObj.someOtherProperty) 

0

Eski bir soru olduğunu biliyorum ama yine de bunu nasıl başardığımı paylaşmak istedim. Yapıcıda durum varsayımı şöyle görünür:

  constructor(props) {
    super(props);

    this.state = {
      loading: false,
      user: {
        email: ""
      },
      organization: {
        name: ""
      }
    };

    this.handleChange = this.handleChange.bind(this);
  }

Benim handleChangefonksiyonum şöyle:

  handleChange(e) {
    const names = e.target.name.split(".");
    const value = e.target.type === "checkbox" ? e.target.checked : e.target.value;
    this.setState((state) => {
      state[names[0]][names[1]] = value;
      return {[names[0]]: state[names[0]]};
    });
  }

Ve girişleri buna göre adlandırdığınızdan emin olun:

<input
   type="text"
   name="user.email"
   onChange={this.handleChange}
   value={this.state.user.firstName}
   placeholder="Email Address"
/>

<input
   type="text"
   name="organization.name"
   onChange={this.handleChange}
   value={this.state.organization.name}
   placeholder="Organization Name"
/>

0

Aramayı azaltma ile iç içe güncellemeler yapıyorum :

Misal:

Durumdaki iç içe değişkenler:

state = {
    coords: {
        x: 0,
        y: 0,
        z: 0
    }
}

İşlev:

handleChange = nestedAttr => event => {
  const { target: { value } } = event;
  const attrs = nestedAttr.split('.');

  let stateVar = this.state[attrs[0]];
  if(attrs.length>1)
    attrs.reduce((a,b,index,arr)=>{
      if(index==arr.length-1)
        a[b] = value;
      else if(a[b]!=null)
        return a[b]
      else
        return a;
    },stateVar);
  else
    stateVar = value;

  this.setState({[attrs[0]]: stateVar})
}

kullanın:

<input
value={this.state.coords.x}
onChange={this.handleTextChange('coords.x')}
/>

0

Bu benim initialState'im

    const initialStateInput = {
        cabeceraFamilia: {
            familia: '',
            direccion: '',
            telefonos: '',
            email: ''
        },
        motivoConsulta: '',
        fechaHora: '',
        corresponsables: [],
    }

Kanca veya durum (sınıf bileşeni) ile değiştirebilirsiniz

const [infoAgendamiento, setInfoAgendamiento] = useState(initialStateInput);

HandleChange yöntemi

const actualizarState = e => {
    const nameObjects = e.target.name.split('.');
    const newState = setStateNested(infoAgendamiento, nameObjects, e.target.value);
    setInfoAgendamiento({...newState});
};

Yuvalanmış durumlarla durum ayarlama yöntemi

const setStateNested = (state, nameObjects, value) => {
    let i = 0;
    let operativeState = state;
    if(nameObjects.length > 1){
        for (i = 0; i < nameObjects.length - 1; i++) {
            operativeState = operativeState[nameObjects[i]];
        }
    }
    operativeState[nameObjects[i]] = value;
    return state;
}

Sonunda kullandığım girdi bu

<input type="text" className="form-control" name="cabeceraFamilia.direccion" placeholder="Dirección" defaultValue={infoAgendamiento.cabeceraFamilia.direccion} onChange={actualizarState} />

0

Projenizde formik kullanıyorsanız, bu şeyleri halletmenin kolay bir yolu vardır. İşte formik ile yapmanın en kolay yolu.

İlk olarak başlangıç ​​değerlerinizi formik initivalues ​​özniteliği içinde veya reaksiyonda ayarlayın. durum

Burada, başlangıç ​​değerleri reaksiyon durumunda tanımlanır

   state = { 
     data: {
        fy: {
            active: "N"
        }
     }
   }

formik initiValuesözniteliğindeki formik alanı için yukarıdaki ilkDeğerleri tanımla

<Formik
 initialValues={this.state.data}
 onSubmit={(values, actions)=> {...your actions goes here}}
>
{({ isSubmitting }) => (
  <Form>
    <Field type="checkbox" name="fy.active" onChange={(e) => {
      const value = e.target.checked;
      if(value) setFieldValue('fy.active', 'Y')
      else setFieldValue('fy.active', 'N')
    }}/>
  </Form>
)}
</Formik>

Durumu ayarlamak için formik işlevi stringyerine güncellendi durumunu kontrol etmek için bir konsol oluşturun veya formik durum değerlerindeki değişiklikleri görmek için debugger aracıyla reaksiyona geçin.booleansetFieldValue


0

bu kodu deneyin:

this.setState({ someProperty: {flag: false} });

Ancak someProperty, yukarıdaki kod yürütüldükten sonra ve yukarıdaki kod yürütüldükten sonra nesnede bulunan diğer tüm özellikleri kaldıracakflag
Yashas

0

bir kitapta şunları gördüm:

this.setState(state => state.someProperty.falg = false);

ama doğru olup olmadığından emin değilim ..

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.