Prop değiştiğinde React bileşenini yeniden işleyin


95

Sunumsal bir bileşeni bir konteyner bileşeninden ayırmaya çalışıyorum. Bir SitesTableve bir var SitesTableContainer. Konteyner, mevcut kullanıcıya bağlı olarak uygun siteleri getirmek için yeniden düzenleme eylemlerini tetiklemekten sorumludur.

Sorun, kapsayıcı bileşeni başlangıçta oluşturulduktan sonra mevcut kullanıcının eşzamansız olarak getirilmesidir. Bu, kapsayıcı bileşeninin, componentDidMountişlevindeki kodu SitesTable,. Props'larından (kullanıcı) biri değiştiğinde konteyner bileşenini yeniden oluşturmam gerektiğini düşünüyorum. Bunu nasıl doğru bir şekilde yaparım?

class SitesTableContainer extends React.Component {
    static get propTypes() {
      return {
        sites: React.PropTypes.object,
        user: React.PropTypes.object,
        isManager: React.PropTypes.boolean
      }
     }

    componentDidMount() {
      if (this.props.isManager) {
        this.props.dispatch(actions.fetchAllSites())
      } else {
        const currentUserId = this.props.user.get('id')
        this.props.dispatch(actions.fetchUsersSites(currentUserId))
      }  
    }

    render() {
      return <SitesTable sites={this.props.sites}/>
    }
}

function mapStateToProps(state) {
  const user = userUtils.getCurrentUser(state)

  return {
    sites: state.get('sites'),
    user,
    isManager: userUtils.isManager(user)
  }
}

export default connect(mapStateToProps)(SitesTableContainer);

sahne değiştiğinde bir şeyi ateşlemek istiyorsanız, componentDidUpdate veya muhtemelen aradığınız, componentWillReceiveProps (nextProps) gibi başka işlevler de kullanabilirsiniz
thsorens

Props'unu değiştirmiyorsa neden SitesTable'ı yeniden düzenlemeniz gerekiyor?
QoP

@QoP, gönderilen eylemler , uygulama durumundaki düğümü componentDidMountdeğiştirecek sitesve SitesTable. SitesStable'ın sitesdüğümü değişecek.
David

Oh, anladım, cevabı yazacağım.
QoP

1
Bunu işlevsel bir bileşende nasıl elde edebilirsiniz
yaswanthkoneri

Yanıtlar:


123

componentDidUpdateYönteminize bir koşul eklemelisiniz .

Örnek, fast-deep-equalnesneleri karşılaştırmak için kullanıyor .

import equal from 'fast-deep-equal'

...

constructor(){
  this.updateUser = this.updateUser.bind(this);
}  

componentDidMount() {
  this.updateUser();
}

componentDidUpdate(prevProps) {
  if(!equal(this.props.user, prevProps.user)) // Check if it's a new user, you can also use some unique property, like the ID  (this.props.user.id !== prevProps.user.id)
  {
    this.updateUser();
  }
} 

updateUser() {
  if (this.props.isManager) {
    this.props.dispatch(actions.fetchAllSites())
  } else {
    const currentUserId = this.props.user.get('id')
    this.props.dispatch(actions.fetchUsersSites(currentUserId))
  }  
}

Kancaları Kullanma (16.8.0+ Tepki)

import React, { useEffect } from 'react';

const SitesTableContainer = ({
  user,
  isManager,
  dispatch,
  sites,
}) => {
  useEffect(() => {
    if(isManager) {
      dispatch(actions.fetchAllSites())
    } else {
      const currentUserId = user.get('id')
      dispatch(actions.fetchUsersSites(currentUserId))
    }
  }, [user]); 

  return (
    return <SitesTable sites={sites}/>
  )

}

Karşılaştırdığınız pervane bir nesne veya diziyse, useDeepCompareEffectbunun yerine kullanmalısınız useEffect.


JSON.stringify'ın yalnızca bu tür bir karşılaştırma için kullanılabileceğini unutmayın, eğer kararlıysa (spesifikasyona göre değildir), bu nedenle aynı girdiler için aynı çıktıyı üretir. Gereksiz yeniden yüklemelerden kaçınmak için kullanıcı nesnelerinin kimlik özelliklerini karşılaştırmanızı veya prop'larda userId-s'leri geçirmenizi ve karşılaştırmanızı öneririm.
László Kardinál

4
Lütfen componentWillReceiveProps yaşam döngüsü yönteminin kullanımdan kaldırıldığını ve muhtemelen React 17'de kaldırılacağını unutmayın. ComponentDidUpdate ve yeni getDerivedStateFromProps yönteminin bir kombinasyonunun kullanılması, React geliştirici ekibinin önerdiği stratejidir. Blog gönderilerinden daha fazlası: reactjs.org/blog/2018/03/27/update-on-async-rendering.html
michaelpoltorak

@QoP React Hooks ile ikinci örnek, her userdeğiştiğinde kaldırılacak ve yeniden bağlanacak mı? Bu ne kadar pahalı?
Robotron

32

ComponentWillReceiveProps()hatalar ve tutarsızlıklar nedeniyle gelecekte kullanımdan kaldırılacaktır. Sahne değişikliği bir bileşeni yeniden oluşturma için alternatif bir çözüm kullanmaktır ComponentDidUpdate()ve ShouldComponentUpdate().

ComponentDidUpdate()bileşen her güncellendiğinde VE eğer ShouldComponentUpdate()doğru döndürürse çağrılır ( ShouldComponentUpdate()Tanımlanmamışsa truevarsayılan olarak döner ).

shouldComponentUpdate(nextProps){
    return nextProps.changedProp !== this.state.changedProp;
}

componentDidUpdate(props){
    // Desired operations: ex setting state
}

Aynı davranış, ComponentDidUpdate()içine koşullu ifade dahil edilerek yalnızca yöntem kullanılarak gerçekleştirilebilir .

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

Durum koşulsuz veya ShouldComponentUpdate()bileşen tanımlanmadan ayarlanmaya çalışılırsa , bileşen sonsuza kadar yeniden oluşturulacaktır.


2
componentWillReceivePropsKullanımdan kaldırılmak üzere olduğu ve kullanıma karşı önerildiği için bu yanıtın yükseltilmesi gerekiyor ( şimdilik en azından) .
AnBisw

İkinci form (componentDidUpdate içindeki koşullu ifade) benim için işe yarıyor, çünkü başka durum değişikliklerinin devam etmesini istiyorum, örneğin bir flaş mesajı kapatmak.
Little Brain

Birisi kodumda shouldComponentUpdate'i kullanmıştı ve soruna neyin sebep olduğunu anlayamadım, bu açıkça ortaya koydu.
steve moretz

14

Sen kullanabilirsiniz KEYsahne ile değişir benzersiz bir anahtar (veri kombinasyonu) ve bu bileşen güncellenen sahne ile yeniden oluşturulur edilecektir.


4
componentWillReceiveProps(nextProps) { // your code here}

Sanırım ihtiyacın olan olay bu. componentWillReceivePropsbileşeniniz sahne aracılığıyla bir şey aldığında tetiklenir. Oradan kontrolünüzü alabilir ve yapmak istediğinizi yapabilirsiniz.


12
componentWillReceivePropskullanımdan kaldırıldı *
Maihan Nijat

3

Bu cevaba bir göz atmanızı ve yaptığınız şeyle alakalı olup olmadığına bakmanızı tavsiye ederim . Gerçek sorununuzu anlarsam, eşzamansız eyleminizi doğru bir şekilde kullanmamanız ve bileşeninizi yeni donanımlarıyla otomatik olarak güncelleyecek olan redux "store" u güncellemenizdir.

Kodunuzun bu bölümü:

componentDidMount() {
      if (this.props.isManager) {
        this.props.dispatch(actions.fetchAllSites())
      } else {
        const currentUserId = this.props.user.get('id')
        this.props.dispatch(actions.fetchUsersSites(currentUserId))
      }  
    }

Bir bileşende tetikleyici olmamalı, ilk isteğinizi yerine getirdikten sonra ele alınmalıdır.

Redux-thunk'tan bu örneğe bir göz atın :

function makeASandwichWithSecretSauce(forPerson) {

  // Invert control!
  // Return a function that accepts `dispatch` so we can dispatch later.
  // Thunk middleware knows how to turn thunk async actions into actions.

  return function (dispatch) {
    return fetchSecretSauce().then(
      sauce => dispatch(makeASandwich(forPerson, sauce)),
      error => dispatch(apologize('The Sandwich Shop', forPerson, error))
    );
  };
}

Redux-thunk kullanmanız gerekmez, ancak bunun gibi senaryolar hakkında mantık yürütmenize ve buna uygun kod yazmanıza yardımcı olur.


doğru, anladım. Ama makeASandwichWithSecretSauce bileşeninizde tam olarak nereye gönderiyorsunuz ?
David

Sizi ilgili bir örnekle bir depoya bağlayacağım, uygulamanızla react-router kullanıyor musunuz?
TameBadger

@David de bu örneğe olan bağlantıyı takdir eder, temelde aynı sorunu yaşıyorum.
SamYoungNY

0

Kullanılması kolay bir yöntem şudur, pervane güncellemeleri bir kez bileşeni otomatik olarak yeniden işleyecektir:

render {

let textWhenComponentUpdate = this.props.text 

return (
<View>
  <Text>{textWhenComponentUpdate}</Text>
</View>
)

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