जब परिवर्तन बदलता है तो रिएक्ट घटक को फिर से प्रस्तुत करें


95

मैं एक कंटेनर घटक से एक प्रस्तुति घटक को अलग करने की कोशिश कर रहा हूं। मेरे पास एक SitesTableऔर एक है SitesTableContainer। वर्तमान उपयोगकर्ता के आधार पर उपयुक्त साइटों को लाने के लिए कंटेनर Redux क्रियाओं को चालू करने के लिए जिम्मेदार है।

समस्या यह है कि वर्तमान उपयोगकर्ता को अतुल्यकालिक रूप से प्राप्त किया जाता है, क्योंकि कंटेनर घटक शुरू में प्रदान किया जाता है। इसका मतलब यह है कि कंटेनर घटक को नहीं पता है कि उसे अपने componentDidMountफ़ंक्शन में कोड को फिर से निष्पादित करने की आवश्यकता है जो डेटा को भेजने के लिए अद्यतन करेगा SitesTable। मुझे लगता है कि जब मेरे प्रॉपर (उपयोगकर्ता) में से एक में बदलाव होता है तो मुझे कंटेनर घटक को फिर से प्रस्तुत करना होगा। मैं इसे सही तरीके से कैसे करूं?

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

आपके पास कुछ अन्य कार्य उपलब्ध हैं, जैसे कि घटकड्यूपडेट, या संभवतया आपकी तलाश में लगने वाली घटकविलीरिविवप्रॉप्स (नेक्स्टप्रॉप्स) यदि आप कुछ फायर करना चाहते हैं, जब प्रॉप्स बदल जाते हैं
थिसॉरस

यदि आप अपने प्रॉपर को नहीं बदल रहे हैं, तो आपको SiteTable को फिर से प्रस्तुत करने की आवश्यकता क्यों है?
QoP

@ क्यूओपी को भेजे जाने वाले कार्यों से अनुप्रयोग स्थिति में नोड componentDidMountबदल जाएगा sites, जिसे में पारित किया गया है SitesTable। SitesStable का sitesनोड बदल रहा होगा।
डेविड

ओह, मैं समझ गया, मैं जवाब लिखने जा रहा हूं।
QoP

1
एक कार्यात्मक घटक में इसे कैसे प्राप्त करें
yaswanthkoneri

जवाबों:


123

आपको अपने componentDidUpdateतरीके में एक शर्त जोड़नी होगी ।

fast-deep-equalवस्तुओं की तुलना करने के लिए उदाहरण का उपयोग किया जाता है।

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

हुक का उपयोग करना (प्रतिक्रिया 16.8.0+)

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

}

यदि आप जिस प्रोप की तुलना कर रहे हैं, वह एक ऑब्जेक्ट या एरे है, तो आपको useDeepCompareEffectइसके बजाय उपयोग करना चाहिए useEffect


ध्यान दें कि JSON.stringify का उपयोग केवल इस तरह की तुलना के लिए किया जा सकता है, यदि यह स्थिर है (विनिर्देश द्वारा ऐसा नहीं है), तो यह समान इनपुट के लिए एक ही आउटपुट का उत्पादन करता है। मैं अनावश्यक वस्तुओं से बचने के लिए, उपयोगकर्ता ऑब्जेक्ट्स के आईडी गुणों की तुलना करने, या प्रॉपर में userId-s पास करने और उनकी तुलना करने की सलाह देता हूं।
लेज़्ज़्लो कारडिनल

4
कृपया ध्यान दें कि ComponentsWillReceiveProps जीवनचक्र विधि को पदावनत किया जाता है और संभवत: रिएक्ट 17 में हटा दिया जाएगा। कंपोनेंटड्यूपडेट के एक संयोजन का उपयोग करके और नए getDerivedStateFromPodspot विधि को रीट देव टीम से सुझाई गई रणनीति है। उनके ब्लॉग पोस्ट में अधिक: reactjs.org/blog/2018/03/27/update-on-async-rendering.html
michaelpoltorak

@QoP दूसरा उदाहरण, रिएक्ट हुक के साथ, क्या यह जब भी userबदलता है तो इसे अनमाउंट और रीमाउंट किया जाएगा ? यह कितना महंगा है?
Robotron

32

ComponentWillReceiveProps()भविष्य में बग्स और विसंगतियों के कारण अपदस्थ होने जा रहा है। सहारा परिवर्तन पर एक घटक को फिर से प्रस्तुत करने के लिए एक वैकल्पिक समाधान का उपयोग करना है ComponentDidUpdate()और ShouldComponentUpdate()

ComponentDidUpdate()जब भी घटक अद्यतनों को कहा जाता है और यदि ShouldComponentUpdate()सही है (यदि ShouldComponentUpdate()यह परिभाषित नहीं है तो यह trueडिफ़ॉल्ट रूप से लौटता है) कहा जाता है।

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

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

यह समान व्यवहार केवल ComponentDidUpdate()विधि का उपयोग करके पूरा किया जा सकता है इसके अंदर सशर्त विवरण शामिल करके।

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

यदि कोई सशर्त या ShouldComponentUpdate()घटक को परिभाषित किए बिना राज्य को निर्धारित करने का प्रयास करता है , तो वह असीम रूप से पुन: रेंडर कर देगा


2
इस उत्तर को अब (कम से कम अभी के लिए) अपग्रेड करने की आवश्यकता है, क्योंकि componentWillReceivePropsइसे हटा दिया जाना है और उपयोग के खिलाफ सुझाव दिया गया है।
अनीसब

दूसरा फ़ॉर्म (कंपोनेंटड्यूपडेट के अंदर सशर्त विवरण) मेरे लिए काम करता है क्योंकि मैं चाहता हूं कि अन्य राज्य परिवर्तन अभी भी हों, जैसे कि एक फ्लैश संदेश को बंद करना।
लिटिल ब्रेन

किसी ने मेरे कोड में shouldComponentUpdate का उपयोग किया था और मैं यह नहीं समझ सका कि इससे क्या समस्या पैदा हो रही है।
मोरेत्ज

14

आप KEYअद्वितीय कुंजी (डेटा का संयोजन) का उपयोग कर सकते हैं जो प्रॉप्स के साथ बदलता है, और उस घटक को अद्यतन प्रॉपर के साथ रेंडर किया जाएगा।


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

मुझे लगता है कि वह घटना है जिसकी आपको आवश्यकता है। componentWillReceivePropsजब भी आपका घटक प्रॉपर के माध्यम से कुछ प्राप्त करता है, तो ट्रिगर होता है। वहां से आप अपनी चेकिंग कर सकते हैं फिर आप जो करना चाहते हैं वह करें।


12
componentWillReceivePropsपदावनत *
मैहन निजात

3

मैं आपके इस उत्तर पर एक नज़र डालने की सलाह दूंगा , और यह देखूंगा कि क्या यह प्रासंगिक है जो आप कर रहे हैं। अगर मुझे आपकी वास्तविक समस्या समझ में आती है, तो यह है कि आपकी बस अपने async कार्रवाई का सही ढंग से उपयोग नहीं कर रहा है और redux "store" को अपडेट कर रहा है, जो कि आपके घटक को नए प्रॉप्स के साथ अपडेट कर देगा।

आपके कोड का यह भाग:

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

एक घटक में ट्रिगर नहीं होना चाहिए, इसे आपके पहले अनुरोध को निष्पादित करने के बाद नियंत्रित किया जाना चाहिए।

Redux-thunk से इस उदाहरण को देखें :

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 का उपयोग करें, लेकिन यह आपको इस तरह के परिदृश्यों के बारे में कारण और मैच लिखने के लिए कोड लिखने में मदद करेगा।


ठीक है, मैं समझ गया लेकिन वास्तव में आप makeASandwichWithSecretSauce अपने घटक में कहां भेजते हैं?
डेविड

मैं आपको एक प्रासंगिक उदाहरण के साथ एक रेपो से जोड़ता हूं, क्या आप अपने ऐप के साथ प्रतिक्रिया-राउटर का उपयोग करते हैं?
तमेबडेर

@ डेविड भी उस उदाहरण के लिंक की सराहना करेंगे, मेरे पास मूल रूप से एक ही मुद्दा है।
संयुग्नि

0

उपयोग करने के लिए एक अनुकूल विधि निम्नलिखित है, एक बार प्रोप अपडेट यह स्वचालित रूप से रेंडरर घटक होगा:

render {

let textWhenComponentUpdate = this.props.text 

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

}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.