जब रूट पैरामीटर बदलते हैं, तो घटक रिमाउंट नहीं होता है


99

मैं प्रतिक्रिया-राउटर का उपयोग करके एक प्रतिक्रिया एप्लिकेशन पर काम कर रहा हूं। मेरे पास एक परियोजना पृष्ठ है जिसमें एक यूआरएल इस प्रकार है:

myapplication.com/project/unique-project-id

जब प्रोजेक्ट कंपोनेंट लोड होता है, तो मैं कंपोनेंटडिमाउंट इवेंट से उस प्रोजेक्ट के लिए डेटा अनुरोध ट्रिगर करता हूं। मैं अब एक ऐसे मुद्दे पर चल रहा हूँ जहाँ अगर मैं सीधे दो परियोजनाओं के बीच स्विच करता हूँ तो केवल आईडी ही इस तरह बदलती है ...

myapplication.com/project/982378632
myapplication.com/project/782387223
myapplication.com/project/198731289

ComponentsDidMount को फिर से ट्रिगर नहीं किया जाता है ताकि डेटा ताज़ा न हो। क्या इस मुद्दे से निपटने के लिए मेरे डेटा अनुरोध या एक अलग रणनीति को ट्रिगर करने के लिए एक और जीवनचक्र घटना है?


1
क्या आप अपने घटक कोड पोस्ट कर सकते हैं?
पियरे क्रिएन्ससी

जवाबों:


81

यदि लिंक केवल एक अलग परम के साथ एक ही मार्ग पर निर्देशित हो रहा है, तो यह रिमाउंटिंग नहीं है, बल्कि नए प्रॉपर प्राप्त कर रहा है। तो, आप componentWillReceiveProps(newProps)फ़ंक्शन का उपयोग कर सकते हैं और देख सकते हैं newProps.params.projectId

यदि आप डेटा लोड करने का प्रयास कर रहे हैं, तो मैं राउटर पर स्थिर तरीकों का उपयोग करके मैच को संभालने से पहले डेटा को लाने की सलाह दूंगा। इस उदाहरण को देखें। प्रतिक्रिया रूटर मेगा डेमो । इस तरह, घटक डेटा को लोड कर देगा और स्वचालित रूप से अपडेट करेगा जब मार्ग परमास पर भरोसा करने की आवश्यकता के बिना बदल जाता है componentWillReceiveProps


2
धन्यवाद। मैं इस काम को करने में सक्षम थाWillReceiveProps का उपयोग कर। मैं अभी भी वास्तव में प्रतिक्रिया रूटर मेगा डेमो डेटा प्रवाह को नहीं समझता। मैं कुछ घटकों पर परिभाषित स्थिर भ्रूण देख रहा हूँ। राउटर क्लाइंट साइड से इन स्टेटिक्स को कैसे बुलाया जा रहा है?
नक्षत्र

1
बड़ा सवाल है। Client.js फ़ाइल और server.js फ़ाइल देखें। राउटर के रन साइकिल के दौरान वे fetchData.js फ़ाइल को कॉल करते हैं और stateइसे पास करते हैं। यह पहली बार में थोड़ा भ्रमित है लेकिन फिर थोड़ा स्पष्ट हो जाता है।
ब्रैड बी

12
FYI करें: "ComponentsWillReceiveProps" को विरासत माना जाता है
इडान डेगन

4
आपको घटक 16 के साथ ComponentDidUpdate का उपयोग करना चाहिए क्योंकि घटक
Pato Loco

1
यह काम करता है, लेकिन समस्या यह है कि आपको डेटा लोड करने वाले हर घटक को पुन: रेंडर करने से निपटने के लिए कंपोनेंटविलेरिवप्रॉप्स () या कंपोनेंटडीड्यूपडेट () को जोड़ने की आवश्यकता है। उदाहरण के लिए उस पृष्ठ के बारे में सोचें जिसमें कई घटक हैं जो समान पथ पैरामीटर के आधार पर डेटा लोड कर रहे हैं।
जूहा सिरजला

98

यदि मार्ग बदलते समय आपको एक घटक रिमाउंट की आवश्यकता होती है, तो आप अपने घटक की मुख्य विशेषता के लिए एक अद्वितीय कुंजी पास कर सकते हैं (कुंजी आपके पथ / मार्ग से संबद्ध है)। इसलिए हर बार जब मार्ग बदलता है, तो कुंजी भी बदल जाएगी जो प्रतिक्रिया घटक को अनमाउंट / रिमाउंट करने के लिए ट्रिगर करती है। मुझे इस उत्तर से विचार आया


2
प्रतिभाशाली! इस सरल और सुरुचिपूर्ण उत्तर के लिए धन्यवाद
Z_z_Z

बस पूछ रहे हैं, क्या इससे ऐप का प्रदर्शन प्रभावित नहीं होगा?
अल्पित आनंद

1
@AlpitAnand यह एक व्यापक प्रश्न है। पुन: बढ़ते निश्चित रूप से पुन: प्रतिपादन की तुलना में धीमा है क्योंकि यह अधिक जीवनचक्र विधियों को ट्रिगर करता है। यहाँ मैं बस जवाब दे रहा हूँ कि मार्ग में परिवर्तन होने पर रीमाउंट कैसे बनाया जाए।
वीई

लेकिन इसका बहुत बड़ा असर नहीं है? व्हाट्सएप आपकी सलाह क्या हम इसे बिना ज्यादा प्रभाव के सुरक्षित रूप से उपयोग कर सकते हैं?
अल्फिट आनंद

@AlpitAnand आपका प्रश्न बहुत व्यापक और विशिष्ट है। कुछ अनुप्रयोगों के लिए, हां, यह एक प्रदर्शन हिट होगा, जिस स्थिति में आपको खुद को बदलते हुए प्रॉपर देखना चाहिए और केवल उन तत्वों को अपडेट करना चाहिए जिन्हें अपडेट करना चाहिए। अधिकांश के लिए, उपरोक्त एक अच्छा समाधान है
क्रिस

84

यहाँ मेरा जवाब है, उपरोक्त में से कुछ के समान लेकिन कोड के साथ।

<Route path="/page/:pageid" render={(props) => (
  <Page key={props.match.params.pageid} {...props} />)
} />

4
यहां कुंजी सबसे बड़ी भूमिका निभाती है, क्योंकि आपके पास प्रोफ़ाइल पृष्ठ में लिंक करने वाली छवि, एक ही मार्ग पर पुनर्निर्देशित करने पर क्लिक करती है, लेकिन अलग-अलग मापदंडों के साथ, लेकिन घटक doesn t अद्यतन को अपडेट करें, क्योंकि प्रतिक्रिया में अंतर नहीं मिल सकता है, क्योंकि पुराने परिणाम की तुलना करने के लिए एक कुंजी होनी चाहिए
जॉर्जी पीव

14

आपको स्पष्ट होना होगा, कि मार्ग परिवर्तन से पृष्ठ ताज़ा नहीं होगा, आपको इसे स्वयं संभालना होगा।

import theThingsYouNeed from './whereYouFindThem'

export default class Project extends React.Component {

    componentWillMount() {

        this.state = {
            id: this.props.router.params.id
        }

        // fire action to update redux project store
        this.props.dispatch(fetchProject(this.props.router.params.id))
    }

    componentDidUpdate(prevProps, prevState) {
         /**
         * this is the initial render
         * without a previous prop change
         */
        if(prevProps == undefined) {
            return false
        }

        /**
         * new Project in town ?
         */
        if (this.state.id != this.props.router.params.id) {
           this.props.dispatch(fetchProject(this.props.router.params.id))
           this.setState({id: this.props.router.params.id})
        }

    }

    render() { <Project .../> }
}

धन्यवाद, यह समाधान मेरे लिए काम करता है। लेकिन मेरी एस्लिन सेटिंग इस बारे में शिकायत कर रही है: github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/… इस बारे में आप क्या सोचते हैं?
कोनकोया

हाँ, यह वास्तव में सबसे अच्छा अभ्यास नहीं है, इसके बारे में खेद है, "fetchProject" भेजने के बाद आपका reducer आपके प्रॉपर को किसी भी तरह से अपडेट कर देगा, मैंने अभी-अभी अपनी जगह बनाने के लिए इसका उपयोग किया है बिना जगह पर redux डाले
चिकनचिल्ली

हाय चिकनचिल्ली, मैं वास्तव में अभी भी इस में फंस गया हूं ... क्या आपके पास अन्य सुझाव या अनुशंसित ट्यूटोरियल हैं? या मैं अभी के लिए आपके समाधान पर टिकूंगा। आपकी सहायताके लिए धन्यवाद!
कोनकोया

12

यदि आपके पास है:

<Route
   render={(props) => <Component {...props} />}
   path="/project/:projectId/"
/>

प्रतिक्रिया में 16.8 और ऊपर, हुक का उपयोग करके , आप कर सकते हैं:

import React, { useEffect } from "react";
const Component = (props) => {
  useEffect(() => {
    props.fetchResource();
  }, [props.match.params.projectId]);

  return (<div>Layout</div>);
}
export default Component;

fetchResourceजब भी आप props.match.params.idपरिवर्तन करते हैं, तो आप केवल एक नए कॉल को चालू कर रहे हैं ।


4
यह बेहतर उत्तर दिया गया है कि अधिकांश अन्य उत्तर अब componentWillReceiveProps
वंचित

8

@Wei, @ ब्रेकपॉइंट 25 और @PaulusLimma के उत्तरों के आधार पर मैंने इस प्रतिस्थापन घटक को बनाया <Route>। यह URL तब बदल जाएगा जब URL बदल जाएगा, पृष्ठ के सभी घटकों को फिर से रेंडर करने के लिए फिर से बनाया और माउंट किया जाएगा। सभी componentDidMount()और अन्य सभी स्टार्टअप हुक URL परिवर्तन पर भी निष्पादित किए जाते हैं।

keyजब URL बदलता है तो घटक संपत्ति को बदलने के लिए विचार होता है और यह घटक को फिर से माउंट करने के लिए प्रतिक्रिया को मजबूर करता है।

आप इसे ड्रॉप-इन प्रतिस्थापन के रूप में उपयोग कर सकते हैं <Route>, उदाहरण के लिए इस तरह:

<Router>
  <Switch>
    <RemountingRoute path="/item/:id" exact={true} component={ItemPage} />
    <RemountingRoute path="/stuff/:id" exact={true} component={StuffPage} />
  </Switch>
</Router>

<RemountingRoute>घटक इस तरह परिभाषित किया गया है:

export const RemountingRoute = (props) => {
  const {component, ...other} = props
  const Component = component
  return (
    <Route {...other} render={p => <Component key={p.location.pathname + p.location.search}
                                              history={p.history}
                                              location={p.location}
                                              match={p.match} />}
    />)
}

RemountingRoute.propsType = {
  component: PropTypes.object.isRequired
}

यह रिएक्ट-राउटर 4.3 के साथ परीक्षण किया गया है।


5

@ वीआई का जवाब बहुत अच्छा काम करता है, लेकिन कुछ स्थितियों में मुझे आंतरिक घटक की कुंजी सेट नहीं करना बेहतर लगता है, लेकिन स्वयं मार्ग। इसके अलावा, अगर घटक के लिए रास्ता स्थिर है, लेकिन आप बस घटक चाहते हैं कि हर बार उपयोगकर्ता इसे नेविगेट करे (शायद घटकडिमाउंट () पर एपी-कॉल करने के लिए), यह मार्ग की कुंजी के लिए location.pathname सेट करना आसान है। स्थान बदलने पर यह मार्ग और सभी सामग्री के साथ मिलता है।

const MainContent = ({location}) => (
    <Switch>
        <Route exact path='/projects' component={Tasks} key={location.pathname}/>
        <Route exact path='/tasks' component={Projects} key={location.pathname}/>
    </Switch>
);

export default withRouter(MainContent)

5

मैंने इस समस्या को हल किया है:

इस विधि को एपीआई से अलग-अलग आइटम मिलता है:

loadConstruction( id ) {
    axios.get('/construction/' + id)
      .then( construction => {
        this.setState({ construction: construction.data })
      })
      .catch( error => {
        console.log('error: ', error);
      })
  }

मैं इस विधि को कंपोनेंटडाउन से कॉल करता हूं, इस विधि को सिर्फ एक बार कॉल किया जाएगा, जब मैं पहली बार इस मार्ग को लोड करता हूं:

componentDidMount() {   
    const id = this.props.match.params.id;
    this.loadConstruction( id )
  }

और ComponentsWillReceiveProps से, जिसे दूसरी बार कॉल करने के बाद से हम एक ही मार्ग लेकिन अलग-अलग आईडी को लोड करते हैं, और मैं राज्य को फिर से लोड करने के लिए पहली विधि कहता हूं और फिर घटक नए आइटम को लोड करेगा।

componentWillReceiveProps(nextProps) {
    if (nextProps.match.params.id !== this.props.match.params.id) {
      const id = nextProps.match.params.id
      this.loadConstruction( id );
    }
  }

यह काम करता है लेकिन समस्या है कि आपको डेटा को लोड करने वाले हर घटक को पुन: रेंडर करने से निपटने के लिए कंपोनेंटवैलिसेपप्रॉप्स () को जोड़ने की आवश्यकता है।
जूहा सिरजला

कंपोनेंटड्यूपडेट (prevProps) का उपयोग करें। ComponentsWillUpdate () ComponentsWillReceiveProps () को हटा दिया जाता है।
मिरेक माइकल

0

यदि आप क्लास कंपोनेंट का उपयोग कर रहे हैं, तो आप कंपोनेंटड्यूपडेट का उपयोग कर सकते हैं

componentDidMount() {
    const { projectId } = this.props.match.params
    this.GetProject(id); // Get the project when Component gets Mounted
 }

componentDidUpdate(prevProps, prevState) {
    const { projectId } = this.props.match.params

    if (prevState.projetct) { //Ensuring This is not the first call to the server
      if(projectId !== prevProps.match.params.projectId ) {
        this.GetProject(projectId); // Get the new Project when project id Change on Url
      }
    }
 }

घटकडिपडेट को अभी हटा दिया गया है, यह अच्छा होगा यदि आप कुछ वैकल्पिक भी सुझा सकते हैं।
साहिल

क्या अापको उस बारे में पूर्ण विशवास है? ComponentDidUpdate नहीं है और आने वाले संस्करण में पदावनत होने वाला नहीं है, क्या आप कुछ लिंक संलग्न कर सकते हैं? इस प्रकार के रूप में पदावनत किए जाने वाले कार्य: कंपोनेंटमिलमाउंट - UNSAFE_componentWillMount घटकWillReceiveProps - UNSAFE_componentWillReceiveProps घटकहिलपाइप
Angel Mas

0

आप प्रदान की गई विधि का उपयोग कर सकते हैं:

useEffect(() => {
  // fetch something
}, [props.match.params.id])

जब मार्ग परिवर्तन के बाद पुन: रेंडर करने के लिए घटक की गारंटी दी जाती है तो आप निर्भरता के रूप में सहारा पास कर सकते हैं

केंट सी डोड्स के अनुसार जो आप देख रहे हैं उसे संभालने के लिए सबसे अच्छा तरीका नहीं बल्कि काफी अच्छा है : जो आप चाहते हैं, उस पर अधिक विचार करें।


-3

react-router टूट गया है क्योंकि यह किसी भी स्थान परिवर्तन पर घटकों को रिमूव करना चाहिए।

मैं हालांकि इस बग के लिए एक समाधान खोजने में कामयाब रहा:

https://github.com/ReactTraining/react-router/issues/1982#issuecomment-275346314

संक्षेप में (पूरी जानकारी के लिए उपरोक्त लिंक देखें)

<Router createElement={ (component, props) =>
{
  const { location } = props
  const key = `${location.pathname}${location.search}`
  props = { ...props, key }
  return React.createElement(component, props)
} }/>

यह इसे किसी भी URL परिवर्तन पर रीमाउंट बना देगा

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