Tepki: prop değiştiğinde alt bileşen neden güncellenmiyor?


137

Neden aşağıdaki sözde kod örneğinde Kapsayıcı foo.bar'ı değiştirdiğinde Child yeniden oluşturmuyor?

Container {
  handleEvent() {
    this.props.foo.bar = 123
  },

  render() {
    return <Child bar={this.props.foo.bar} />
}

Child {
  render() {
    return <div>{this.props.bar}</div>
  }
}

forceUpdate()Kapsayıcıdaki değeri değiştirdikten sonra çağırsam bile , Çocuk hala eski değeri gösteriyor.


5
Bu senin kodun mu? Geçerli bir React kodu değilmiş gibi görünüyor

Props değerinin konteyner bileşeninde değişmemesi gerektiğini, bunun yerine setState tarafından üst bileşende değişiklik olması gerektiğini ve bu durumun konteyner props ile eşlenmesi gerektiğini düşünüyorum
Piyush Patel

Yayılma işlecini şu şekilde kullanın <Child bar = {... this.props.foo.bar} />
Sourav Singh

@AdrianWydmanski ve oy kullanan diğer 5 kişi: en.wikipedia.org/wiki/Pseudocode
David Newcomb

@PiyushPatel props, sözde kod örneğinin gösterdiği gibi bir bileşen yerinde yeniden oluşturulduğunda güncellenir. Bunun başka bir örneği, kullanmak gibi <Route exact path="/user/:email" component={ListUserMessagePage} />bir şeydir , aynı sayfadaki bir bağlantı, yeni bir örnek oluşturmadan ve normal yaşam döngüsü olaylarını çalıştırmadan props'ı güncelleyecektir.
David Newcomb

Yanıtlar:


94

Alt öğe, "anahtar" özniteliği ada eşit olacak şekilde güncelleyin. Bileşen, anahtar her değiştiğinde yeniden oluşturulur.

Child {
  render() {
    return <div key={this.props.bar}>{this.props.bar}</div>
  }
}

5
Bunun için teşekkürler. Redux deposunu kullanıyordum ve bir anahtar ekleyene kadar bileşenimin yeniden işlenmesini sağlayamadım. (Rasgele anahtar oluşturmak için uuid kitaplığını kullandım ve işe yaradı).
Maiya

Kancaları kullanarak çocuğum, mevcut bir dizide durumu ayarlarken yeniden oluşturmaz. Benim (muhtemelen kötü bir fikir) kesmek aynı anda bir kukla pervane durumunu ayarlamak ve useEffect bağımlılık diziye eklemek oldu: [props.notRenderingArr, props.dummy]. Dizinin uzunluğu her zaman değişirse, useEffect bağımlılık dizisini olarak ayarlayabilirsiniz [props.notRenderingArr.length].
hipnosis

5
bu benim de ihtiyacım olan şeydi. Şaşkınım, ne zaman keygerekli, sadece setStatemi? Ebeveynlerin durumuna güvenen bazı çocuklarım var, ancak bunlar yeniden oluşturmayı tetiklemiyor ...
dcsan

Mükemmel cevap. Ama neden bu davranış?
Rishav

1
İndeksi anahtar olarak kullanıyordum ama düzgün çalışmıyordu. Şimdi uuid kullanıyorum ve mükemmel :) @Maiya'ya teşekkürler
Ali Rehman

91

Çünkü çocuklar, ebeveynin sahne öğeleri değişirse, ancak STATE değişirse yeniden işlemez :)

Gösterdiğiniz şey şudur: https://facebook.github.io/react/tips/communicate-between-components.html

Verileri props aracılığıyla ebeveynden çocuğa aktarır, ancak orada yeniden oluşturma mantığı yoktur.

Ebeveyn için bir durum ayarlamanız ve ardından çocuğu ebeveyn değişim durumuna ayarlamanız gerekir. Bu yardımcı olabilir. https://facebook.github.io/react/tips/expose-component-functions.html


6
Neden setState yeniden oluşturmaya neden olurken forceUpdate neden olmaz? Ayrıca konu dışı çok az, ancak props redux'den geçildiğinde ve durumu eylem yoluyla güncellendiğinde bileşenler nasıl güncellenir?
Tuomas Toivonen

1
Bileşeni güncelleseniz bile aksesuarlar güncellenmez, geçirdiğiniz aksesuarlar hala orada kalır. Flux başka bir konu evet :)
François Richard

3
state! = props bununla ilgili daha fazla okumalısınız. Sahne ile güncelleme yapmazsınız
François Richard

bunu doğrudan kaynak kodda görebilirsiniz, bu aynı süreç değil
Webwoman

yani burada söyledikleriniz ya değiştirildi ya da doğru anlamadım, bu
ILoveReactAndNode

52

Ben de aynı sorunu yaşadım. Bu benim çözümüm, bunun iyi uygulama olduğundan emin değilim, değilse söyle:

state = {
  value: this.props.value
};

componentDidUpdate(prevProps) {
  if(prevProps.value !== this.props.value) {
    this.setState({value: this.props.value});
  }
}

UPD: Artık aynı şeyi React Hooks kullanarak yapabilirsiniz: (yalnızca bileşen bir işlevse)

const [value, setValue] = useState(propName);
// This will launch only if propName value has chaged.
useEffect(() => { setValue(propName) }, [propName]);

3
Bu kesinlikle doğru cevap, en basitinden bahsetmiyorum bile
Guilherme Ferreira

1
Ben de bu yaklaşımı kullanıyorum.
2019

@ vancy-pants componentDidUpdateBu durumda, Alt bileşenine gider.
Nick Friskel

4
Props'u bir alt bileşende duruma dönüştürmeniz gerekmez ve dönüştürmemelisiniz. Sadece sahne malzemelerini doğrudan kullanın. Gelen FunctionComponentsbunun otomatik sahne değişim eğer çocuk bileşenleri günceller.
oemera

1
Bu yaklaşım aynı zamanda, üst durumdan türetilen alt bileşenlerde destekleriniz olduğunda da işe
yarar

11

React felsefesine göre bileşen, sahne alanını değiştiremez. ebeveynden alınmalı ve değişmez olmalıdır. Yalnızca ebeveyn, çocuklarının dekorlarını değiştirebilir.

devlet vs sahne hakkında güzel açıklama

ayrıca, bu konuyu okuyun React.js'de propları neden güncelleyemiyorum?


Bu aynı zamanda konteynerin redux mağazasından aldığı malzemeleri değiştiremeyeceği anlamına gelmiyor mu?
Tuomas Toivonen

3
Konteyner, malzemeleri doğrudan mağazadan almaz, bir redux durum ağacının bir bölümünü okuyarak sağlanır (kafa karıştırıcı ??). !! kafa karışıklığı, react-redux ile bağlanın sihirli işlevi hakkında bir şey bilmememizdir. connect yönteminin kaynak kodunu görürseniz, temelde storeState özelliğine sahip bir duruma sahip ve redux mağazasına abone olan daha yüksek bir bileşen oluşturur. storeState değiştikçe, tüm yeniden oluşturma gerçekleşir ve değiştirilen props, değiştirilen durumu okuyarak konteynere sağlanır. umarım bu soruya cevap verir
Sujan Thakare

İyi bir açıklama, üst düzey bileşen hakkında düşünmek neler olduğunu anlamama yardımcı oluyor
Tuomas Toivonen

7

setStateFonksiyonu kullanmalısınız . Değilse, forceUpdate'i nasıl kullanırsanız kullanın, durum değişikliğinizi kaydetmez.

Container {
    handleEvent= () => { // use arrow function
        //this.props.foo.bar = 123
        //You should use setState to set value like this:
        this.setState({foo: {bar: 123}});
    };

    render() {
        return <Child bar={this.state.foo.bar} />
    }
    Child {
        render() {
            return <div>{this.props.bar}</div>
        }
    }
}

Kodunuz geçerli görünmüyor. Bu kodu test edemiyorum.


Olması gerekmiyor <Child bar={this.state.foo.bar} />mu?
Josh Broadhurst

Sağ. Cevabı güncelliyorum. Ama dediğim gibi bu geçerli bir kod olmayabilir. Sadece sorudan kopyalayın.
JamesYin

5

React bileşenlerini functionsve useState.

const [drawerState, setDrawerState] = useState(false);

const toggleDrawer = () => {
      // attempting to trigger re-render
      setDrawerState(!drawerState);
};

Bu does not işleri

         <Drawer
            drawerState={drawerState}
            toggleDrawer={toggleDrawer}
         />

Bu işe yarıyor (anahtar ekleyerek)

         <Drawer
            drawerState={drawerState}
            key={drawerState}
            toggleDrawer={toggleDrawer}
         />

4

Onaylandı, Anahtar eklemek işe yarıyor. Nedenini anlamaya çalışmak için belgelerin üzerinden geçtim.

React, alt bileşenler oluştururken verimli olmak ister. Başka bir alt öğe ile aynıysa yeni bir bileşen oluşturmaz, bu da sayfanın daha hızlı yüklenmesini sağlar.

Bir Anahtar eklemek React'i yeni bir bileşen oluşturmaya zorlar ve böylece bu yeni bileşen için Durum'u sıfırlar.

https://reactjs.org/docs/reconciliation.html#recursing-on-children


1

SetState işlevini kullanın. Böylece yapabilirsin

       this.setState({this.state.foo.bar:123}) 

handle olay yönteminin içinde.

Durum güncellendikten sonra değişiklikleri tetikleyecek ve yeniden oluşturma gerçekleşecektir.


1
Bu this.setState ({foo.bar:123}) olmalı, değil mi?
Charith Jayasanka

Bu derlenmeyecek bile ⬆. Sanırım şunu demek istediniz: this.setState ({foo: {bar: 123}})
Avius

0

Herhangi bir durumu korumazsa ve basitçe sahne donanımını işler ve sonra onu ebeveynden çağırırsa, muhtemelen Çocuğu işlevsel bileşen olarak yapmalısınız. Buna alternatif, durum bilgisiz bileşenin yeniden oluşturulmasına neden olacak işlevsel bileşenle (useState) kancalar kullanabilmenizdir.

Ayrıca propaları değişmez olduklarından değiştirmemelisiniz. Bileşenin durumunu koruyun.

Child = ({bar}) => (bar);

0

Ben de aynı problemle karşılaşıyordum. Destek Tooltipalan bir bileşenim vardı , bir koşula bağlı olarak bileşen üzerinde güncelleme yapıyordum, bileşende güncelleniyordu ancak bileşen oluşturulmuyordu.showTooltipParentifParentTooltip

const Parent = () => {
   let showTooltip = false;
   if(....){ showTooltip = true; }
   return(
      <Tooltip showTooltip={showTooltip}></Tooltip>
   )
}

Yaptığım hata showTooltipizin olarak ilan etmekti .

Neyi yanlış yaptığımı anladım Rendering'in nasıl çalıştığına dair ilkeleri ihlal ediyordum, onu kancalarla değiştirmek işi yaptı.

const [showTooltip, setShowTooltip] =  React.useState<boolean>(false);

0

alt bileşendeki connect yönteminin mapStateToProps'unda değişen props tanımlayın.

function mapStateToProps(state) {
  return {
    chanelList: state.messaging.chanelList,
  };
}

export default connect(mapStateToProps)(ChannelItem);

Benim durumumda, channelList'in kanalı güncellendi, bu yüzden mapStateToProps'a chanelList ekledim


0
export default function DataTable({ col, row }) {
  const [datatable, setDatatable] = React.useState({});
  useEffect(() => {
    setDatatable({
      columns: col,
      rows: row,
    });
  /// do any thing else 
  }, [row]);

  return (
    <MDBDataTableV5
      hover
      entriesOptions={[5, 20, 25]}
      entries={5}
      pagesAmount={4}
      data={datatable}
    />
  );
}

bu örnek useEffect, değiştirildiğinde durumu propsdeğiştirmek için kullanılır.

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.