Kullanım Etkisi kancası içinde durumu ayarlayabilir miyim


115

Diyelim ki başka bir duruma bağlı olan bir durumum var (örneğin, A değiştiğinde B'nin değiştirmesini istiyorum).

Etkili kancanın içinde A'yı gözlemleyen ve B'yi ayarlayan bir kanca oluşturmak uygun mudur?

Efektler, düğmeye tıkladığımda ilk efekt patlayacak ve b'nin değişmesine neden olacak ve bir sonraki işlemeden önce ikinci efektin ateşlenmesine neden olacak mı? Böyle bir kod yapılandırmanın herhangi bir performans olumsuz yanı var mı?

let MyComponent = props => {
  let [a, setA] = useState(1)
  let [b, setB] = useState(2)
  useEffect(
    () => {
      if (/*some stuff is true*/) {
        setB(3)
      }
    },
    [a],
  )
  useEffect(
    () => {
      // do some stuff
    },
    [b],
  )

  return (
    <button
      onClick={() => {
        setA(5)
      }}
    >
      click me
    </button>
  )
}

Yanıtlar:


32

Bir efektin içinde setState ayarlasanız bile, efektler her zaman oluşturma aşaması tamamlandıktan sonra yürütülür, başka bir efekt güncellenmiş durumu okuyacak ve yalnızca oluşturma aşamasından sonra üzerinde işlem yapacaktır.

bBaşka nedenlerden dolayı değişebilecek bir olasılık olmadığı sürece her iki eylemi de aynı etkide gerçekleştirmenin muhtemelen daha iyi olduğunu söyleyerek , changing abu durumda da aynı mantığı yürütmek isteyeceksiniz.


4
Öyleyse A, B'yi değiştirirse, bileşen iki kez doğru render eder mi?
Dan Ruswick

2
Ayrıca yukarıdaki sorunun cevabını da bilmek istiyorum
alaboudi

2
@alaboudi Evet, eğer A, B'yi ayarlayan kullanım etkisinin çalışmasına neden olan bir değişiklik olursa, bileşen iki kez işliyor
Shubham Khatri

95

Genel olarak, setStateiçini kullanmak useEffect, büyük olasılıkla neden olmak istemeyeceğiniz sonsuz bir döngü oluşturacaktır. Bu kuralın daha sonra gireceğim birkaç istisna var.

useEffecther işlemeden sonra çağrılır ve setStateiçinde kullanıldığında, bileşenin yeniden oluşturulmasına neden olur, bu da çağırır useEffectvb.

useStateİçini kullanmanın useEffectsonsuz bir döngüye neden olmayacağı popüler durumlardan biri, useEffectbeğenmek için ikinci bir argüman olarak boş bir dizi ilettiğinizde useEffect(() => {....}, []), efekt işlevinin bir kez çağrılması gerektiği anlamına gelir: yalnızca ilk bağlama / oluşturmadan sonra. Bu, bir bileşende veri getirirken ve istek verilerini bileşenin durumunda kaydetmek istediğinizde yaygın olarak kullanılır.


3
Kullanım için başka vaka setStateiçeriden useEffectolduğu setting stateabonelik veya olay dinleyicileri içeride. Ancak aboneliğinizi iptal etmeyi unutmayın reactjs.org/docs/hooks-effect.html#effects-with-cleanup
timqian

31
Bu kesinlikle doğru değildir - useState yalnızca durumu güncellediğiniz değer öncekinden farklıysa tetiklenir, bu nedenle döngüler arasında değer değişmedikçe sonsuz bir döngü engellenir.
RobM

14
Bu cevap yanlıştır ve sorunun amacına uygun değildir: bu durumda, bileşen, düğme tıklandığında yalnızca iki kez oluşturulur, sonsuz döngü yoktur
Bogdan D

14
UseEffect içinde durumu ayarlamak çok yaygın bir kullanım örneğidir. Veri yüklemeyi düşünün, useEffect API'yi çağırır, verileri alır, useState'in set bölümünü kullanarak ayarlar.
badbod99

3
Cevabı, bahsettiğiniz sorunları ele alacak şekilde güncelledim, şimdi daha mı iyi?
Hossam Mourad

52

Gelecekteki amaçlar için bu da yardımcı olabilir:

SetState'i kullanmakta bir sakınca yok, useEffectsadece bir döngü oluşturmamak için zaten açıklandığı gibi dikkat etmeniz gerekiyor.

Ancak ortaya çıkabilecek tek sorun bu değil. Aşağıya bakınız:

Ebeveynden alan ve durumunu ayarlamak istediğiniz bir değişikliğe göre bir bileşeniniz Compolduğunu hayal edin . Bazı nedenlerden dolayı, her bir pervane için farklı bir değişiklik yapmanız gerekir :propspropsCompuseEffect

BUNU YAPMA

useEffect(() => {
  setState({ ...state, a: props.a });
}, [props.a]);

useEffect(() => {
  setState({ ...state, b: props.b });
}, [props.b]);

Bu örnekte görebileceğiniz gibi a'nın durumunu asla değiştirmeyebilir: https://codesandbox.io/s/confident-lederberg-dtx7w

Çünkü bu, bu örnekte gerçekleşmesi nedeni bu kadar hem useEffects aynı çalıştırmak döngüsü tepki hem değiştirdiğinizde prop.ave prop.bdeğeri böylece {...state}bunu yaptığında setStatetam ikisinde de aynıdır useEffect, aynı bağlamda çünkü. İkinciyi çalıştırdığınızda setState, ilkinin yerini alacaktır setState.

BUNU YERİNE YAPIN

Bu sorunun çözümü temelde şöyle adlandırılır setState:

useEffect(() => {
  setState(state => ({ ...state, a: props.a }));
}, [props.a]);

useEffect(() => {
  setState(state => ({ ...state, b: props.b }));
}, [props.b]);

Çözümü buradan kontrol edin: https://codesandbox.io/s/mutable-surf-nynlx

Artık setState. İle devam ettiğinizde her zaman eyaletin en güncel ve doğru değerini alırsınız .

Umarım bu birine yardımcı olur!


2
yukarıdaki çözüm bana yardımcı oldusetName(name => ({ ...name, a: props.a }));
mufaddal_mw

1
bu, ok işlevli bölümde de bana yardımcı oldusetItems(items => [...items, item])
Stefan Zhelyazkov

Vay canına, harikasın. Bugün benim a * larımı kurtardın.
Pratik Soni

Bir çözüm bulamadan sabah 7'den akşam 3'e kadar geçirdim ve şimdi beni kurtardın.
Dinindu Kanchana

21

useEffectbelirli bir pervane veya duruma bağlanabilir. bu nedenle, sonsuz döngü kancasından kaçınmak için yapmanız gereken şey, bazı değişkenleri veya durumları etkilemektir.

Örneğin:

useEffect(myeffectCallback, [])

Yukarıdaki efekt, yalnızca bileşen oluşturulduktan sonra tetiklenir. bu componentDidMountyaşam döngüsüne benzer

const [something, setSomething] = withState(0)
const [myState, setMyState] = withState(0)
useEffect(() => {
  setSomething(0)
}, myState)

Yukarıdaki etki yalnızca benim durumumda ateşlenecek, buna benzer, componentDidUpdateancak değişen her durum onu ​​ateşlemeyecek.

Bu bağlantıya rağmen daha fazla ayrıntı okuyabilirsiniz


Teşekkürler, bu cevap, useEffect'in bağımlılık dizisini diğer cevapların yapmadığı bir şekilde ele almaktadır. UseEffect'e ikinci bir argüman olarak boş bir dizinin dahil edilmesi, useEffect'in bileşen oluşturulduktan sonra yürütüldüğünden emin olmanızı sağlar, ancak belirli bir duruma veya belirli durumlara sahip bir dizinin dahil edilmesi, başvurudaki durumlar değiştiğinde useEffect'in yürütülmesine neden olur.
adriaanbd

10

▶ 1. Kullanım Etkisi kancası içinde durumu ayarlayabilir miyim?

Prensip olarak, içinde useEffectve hatta işleme sırasında bile, ihtiyacınız olan yerde durumu özgürce ayarlayabilirsiniz . Hook'u depsdoğru bir şekilde ayarlayarak ve / veya koşullu olarak sonsuz döngülerden kaçındığınızdan emin olun .


▶ 2. Başka bir duruma bağlı olan bir durumum olduğunu varsayalım. Etkili kancanın içinde A'yı gözlemleyen ve B'yi ayarlayan bir kanca oluşturmak uygun mudur?

Sadece açıklanan klasik kullanım örneğini için :useReducer

useReducergenellikle tercih edilir useStateEğer varsa karmaşık hal içerir mantığı birden çok alt değer veya bir sonraki devlet öncekine bağlıdır zaman. ( Tepki belgeleri )

Bir ayarlarken devlet değişkeni bağlıdır bugünkü değerinden başka devlet değişkeni, sen hem bunların yerine denemek isteyebilirsiniz useReducer. [...] Kendinizi yazarken bulduğunuzda setSomething(something => ...), bunun yerine bir azaltıcı kullanmayı düşünmenin tam zamanı. ( Dan Abramov, Aşırı tepki blog )


▶ 3. Efektler, düğmeye tıkladığımda ilk efekt yanacak ve b'nin değişmesine neden olacak ve bir sonraki işlemeden önce ikinci efektin ateşlenmesine neden olacak mı?

useEffecther zaman işleme tamamlandıktan ve DOM değişiklikleri uygulandıktan sonra çalışır . İlk efekt tetiklenir, değişir bve yeniden oluşturmaya neden olur. Bu oluşturma tamamlandıktan sonra, bdeğişiklikler nedeniyle ikinci efekt çalışacaktır .


▶ 4. Böyle bir kod yapılandırmanın performans açısından olumsuz yanları var mı?

Evet. Bir durum değişikliğini sarma ile bayrı bir useEffectiçin abu etkiler potansiyel olarak kullanıcı için görebilir -, tarayıcı ek düzen / boya faza sahiptir. useReducerDenemek istemenin bir yolu yoksa , bdurumu adoğrudan şu şekilde değiştirebilirsin :

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.