প্রতিক্রিয়া - আনমাউন্টযুক্ত উপাদানগুলিতে সেটস্টেট ()


92

আমার প্রতিক্রিয়া উপাদানটিতে আমি একটি সাধারণ স্পিনার প্রয়োগ করার চেষ্টা করছি যখন একটি এজাক্স অনুরোধ চলছে - আমি লোডিংয়ের স্থিতি সঞ্চয় করতে রাষ্ট্র ব্যবহার করছি।

কিছু কারণে আমার প্রতিক্রিয়া উপাদানটিতে নীচের এই কোডটির এই অংশটি এই ত্রুটিটি ছুঁড়েছে

কেবল একটি মাউন্ট করা বা মাউন্টিং উপাদান আপডেট করতে পারে। এর অর্থ সাধারণত আপনি আনমাউন্টযুক্ত উপাদানগুলিতে সেটস্টেট () বলে called এটি কোনও অপশন নয়। অপরিবর্তিত উপাদানটির জন্য দয়া করে কোডটি পরীক্ষা করুন।

আমি যদি প্রথম সেটস্টেট কল থেকে মুক্তি পাই তবে ত্রুটিটি চলে যায়।

constructor(props) {
  super(props);
  this.loadSearches = this.loadSearches.bind(this);

  this.state = {
    loading: false
  }
}

loadSearches() {

  this.setState({
    loading: true,
    searches: []
  });

  console.log('Loading Searches..');

  $.ajax({
    url: this.props.source + '?projectId=' + this.props.projectId,
    dataType: 'json',
    crossDomain: true,
    success: function(data) {
      this.setState({
        loading: false
      });
    }.bind(this),
    error: function(xhr, status, err) {
      console.error(this.props.url, status, err.toString());
      this.setState({
        loading: false
      });
    }.bind(this)
  });
}

componentDidMount() {
  setInterval(this.loadSearches, this.props.pollInterval);
}

render() {

    let searches = this.state.searches || [];


    return (<div>
          <Table striped bordered condensed hover>
          <thead>
            <tr>
              <th>Name</th>
              <th>Submit Date</th>
              <th>Dataset &amp; Datatype</th>
              <th>Results</th>
              <th>Last Downloaded</th>
            </tr>
          </thead>
          {
          searches.map(function(search) {

                let createdDate = moment(search.createdDate, 'X').format("YYYY-MM-DD");
                let downloadedDate = moment(search.downloadedDate, 'X').format("YYYY-MM-DD");
                let records = 0;
                let status = search.status ? search.status.toLowerCase() : ''

                return (
                <tbody key={search.id}>
                  <tr>
                    <td>{search.name}</td>
                    <td>{createdDate}</td>
                    <td>{search.dataset}</td>
                    <td>{records}</td>
                    <td>{downloadedDate}</td>
                  </tr>
                </tbody>
              );
          }
          </Table >
          </div>
      );
  }

প্রশ্নটি হল যে আমি যখন এই উপাদানটি ইতিমধ্যে মাউন্ট করা উচিত (ততটি উপাদানটি ডিডমাউন্ট থেকে আহ্বান করা হচ্ছে) তখন কেন আমি এই ত্রুটিটি পাচ্ছি?


আমার কনস্ট্রাক্টরে আমি "this.loadSearches = this.loadSearches.bind (এটি) স্থাপন করছি"; - অসুস্থতার সাথে প্রশ্নটি যুক্ত করুন
মার্টি

আপনি কি আপনার কনস্ট্রাক্টরে লোড সেট করার চেষ্টা করেছেন ? এটা কাজ করতে পারে। this.state = { loading : null };
বজ্রাচার্য

উত্তর:


69

রেন্ডার ফাংশন না দেখে কিছুটা শক্ত। যদিও আপনার করা উচিত এমন কিছু ইতিমধ্যে স্পট করতে পারে, আপনি যখনই কোনও বিরতি ব্যবহার করেন তখনই এটি আনমাউন্ট থেকে সাফ করতে পারেন। সুতরাং:

componentDidMount() {
    this.loadInterval = setInterval(this.loadSearches, this.props.pollInterval);
}

componentWillUnmount () {
    this.loadInterval && clearInterval(this.loadInterval);
    this.loadInterval = false;
}

যেহেতু সেই সাফল্য এবং ত্রুটি কলব্যাকগুলি এখনও আনমাউন্টের পরে কল হতে পারে, তাই আপনি অন্তর্ভুক্ত ভেরিয়েবলটি এটি মাউন্ট করা হয়েছে কিনা তা পরীক্ষা করতে ব্যবহার করতে পারেন।

this.loadInterval && this.setState({
    loading: false
});

আশা করি এটি সহায়তা করে, যদি কাজটি না করে তবে রেন্ডার ফাংশন সরবরাহ করুন।

চিয়ার্স


4
ব্রুনো, আপনি কেবল "এই" প্রসঙ্গের অস্তিত্বের জন্য পরীক্ষা করতে পারেন নি .. এই ও এই && এই.সেট স্টেট .....
জেমস ইমানন

7
বা সহজভাবে:componentWillUnmount() { clearInterval(this.loadInterval); }
গ্রেগ হার্বোবাইজ

@ গ্রেগহর্বাউইচস যদি আপনি টাইমারের সাথে উপাদানটি আনমাউন্ট করে না রেখে এবং মাউন্ট করে চলেছেন তবে আপনি সাধারণ সাফাই সাফ করলেও এটি বহিস্কার করা যেতে পারে।
করলাজ

14

প্রশ্নটি হল যে আমি যখন এই উপাদানটি ইতিমধ্যে মাউন্ট করা উচিত (ততটি উপাদানটি ডিডমাউন্ট থেকে আহ্বান করা হচ্ছে) তখন কেন আমি এই ত্রুটিটি পাচ্ছি?

এটা থেকে বলা হয় নাcomponentDidMount । আপনার componentDidMountকলব্যাক ফাংশন তৈরি হয়েছে যা টাইমার হ্যান্ডলারের স্ট্যাকের মধ্যে স্ট্যাকের মধ্যে কার্যকর করা হবে componentDidMount। স্পষ্টতই, আপনার কলব্যাক ( this.loadSearches) সম্পাদন হওয়ার সাথে সাথে উপাদানটি আনমাউন্ট হবে।

সুতরাং গৃহীত উত্তর আপনাকে রক্ষা করবে। আপনি যদি এমন কিছু অন্যান্য অ্যাসিনক্রোনাস এপিআই ব্যবহার করছেন যা আপনাকে অ্যাসিক্রোনাস ফাংশনগুলি বাতিল করতে দেয় না (ইতিমধ্যে কিছু হ্যান্ডলারের কাছে জমা দেওয়া হয়েছে) আপনি নিম্নলিখিতটি করতে পারেন:

if (this.isMounted())
     this.setState(...

এটি আপনার ক্ষেত্রে যে ত্রুটি বার্তাটি প্রতিবেদন করবে তা থেকে মুক্তি পাবে যদিও এটি রাগের নীচে ঝোলা জিনিসগুলি মনে হচ্ছে, বিশেষত যদি আপনার এপিআই একটি বাতিল ক্ষমতা সরবরাহ করে (যেমন setIntervalকরে তবে clearInterval)।


13
isMountedফেসবুকে ব্যবহার না করার পরামর্শ দেয় এমন একটি অ্যান্টিপ্যাটার্ন: ফেসবুক.
মার্টি

4
হ্যাঁ, আমি বলি যে "এটি রাগের নীচে ঝোলা জিনিস মনে হচ্ছে"।
মার্কাস জুনিয়াস ব্রুটাস

5

যার কাছে অন্য বিকল্পের প্রয়োজন, রেফ অ্যাট্রিবিউটের কলব্যাক পদ্ধতিটি কার্যকারণ হতে পারে। হ্যান্ডেলফের প্যারামিটার হ'ল ডিওএম উপাদানটির রেফারেন্স।

রেফ এবং ডিওএম সম্পর্কে বিশদ তথ্যের জন্য: https://facebook.github.io/react/docs/refs-and-the-dom.html

handleRef = (divElement) => {
 if(divElement){
  //set state here
 }
}

render(){
 return (
  <div ref={this.handleRef}>
  </div>
 )
}

4
কার্যকরভাবে "ইসমাউন্টেড" এর জন্য একটি রেফ ব্যবহার করা ঠিক ইসমাউন্ডে ব্যবহার করা ঠিক যেমন একই জিনিস তবে কম পরিষ্কার। আইসমাউন্টটি তার নামের কারণে কোনও অ্যান্টি-প্যাটার্ন নয় তবে একটি আনমাউন্টযুক্ত উপাদানটির রেফারেন্স রাখা এটি একটি অ্যান্টি-প্যাটার্ন।
পাজান

3
class myClass extends Component {
  _isMounted = false;

  constructor(props) {
    super(props);

    this.state = {
      data: [],
    };
  }

  componentDidMount() {
    this._isMounted = true;
    this._getData();
  }

  componentWillUnmount() {
    this._isMounted = false;
  }

  _getData() {
    axios.get('https://example.com')
      .then(data => {
        if (this._isMounted) {
          this.setState({ data })
        }
      });
  }


  render() {
    ...
  }
}

একটি কার্যকরী উপাদান জন্য এটি অর্জন করার কোন উপায় আছে? @ জোহন_পার
তামজিদ

কোনও ফাংশনের অংশের জন্য আমি রেফ: কনস্ট্যান্ড_আইসেমাউন্টেড = ইউজারফ (মিথ্যা) ব্যবহার করব; @ তামজিদ
জন_পিপি

1

উত্তরোত্তর জন্য,

এই ত্রুটিটি, আমাদের ক্ষেত্রে, রিফ্লাক্স, কলব্যাকস, পুনর্নির্দেশ এবং সেটস্টেট সম্পর্কিত। আমরা একটি অনডোন কলব্যাকের জন্য একটি সেটস্টেট পাঠিয়েছিলাম, তবে আমরা অনস্যাক্সেস কলব্যাকে একটি পুনর্নির্দেশও প্রেরণ করেছি। সাফল্যের ক্ষেত্রে, আমাদের অনস্যাক্সেস কলব্যাক অন ডনের আগেই কার্যকর করে । এটি চেষ্টা করা সেটস্টেটের আগে পুনর্নির্দেশের কারণ ঘটায় । এইভাবে ত্রুটি, একটি আনমাউন্টযুক্ত উপাদানগুলিতে সেটস্টেট।

রিফ্লাক্স স্টোর অ্যাকশন:

generateWorkflow: function(
    workflowTemplate,
    trackingNumber,
    done,
    onSuccess,
    onFail)
{...

ঠিক করার আগে কল করুন:

Actions.generateWorkflow(
    values.workflowTemplate,
    values.number,
    this.setLoading.bind(this, false),
    this.successRedirect
);

ঠিক করার পরে কল করুন:

Actions.generateWorkflow(
    values.workflowTemplate,
    values.number,
    null,
    this.successRedirect,
    this.setLoading.bind(this, false)
);

আরও

কিছু ক্ষেত্রে, যেহেতু রিএ্যাক্টস এর মাউন্টটি "অবচিত / অ্যান্টি-প্যাটার্ন", তাই আমরা _সামেন্টযুক্ত ভেরিয়েবলের ব্যবহার গ্রহণ করেছি এবং এটি নিজে পর্যবেক্ষণ করছি।


1

প্রতিক্রিয়া হুক দ্বারা সক্ষম একটি সমাধান ভাগ করুন ।

React.useEffect(() => {
  let isSubscribed = true

  callApi(...)
    .catch(err => isSubscribed ? this.setState(...) : Promise.reject({ isSubscribed, ...err }))
    .then(res => isSubscribed ? this.setState(...) : Promise.reject({ isSubscribed }))
    .catch(({ isSubscribed, ...err }) => console.error('request cancelled:', !isSubscribed))

  return () => (isSubscribed = false)
}, [])

যখনই আপনি আইডি পরিবর্তনগুলি আনতে পূর্ববর্তী অনুরোধগুলি বাতিল করতে চান একই সমাধানটি বাড়ানো যেতে পারে , অন্যথায় একাধিক ইন-ফ্লাইট অনুরোধগুলির মধ্যে (জাতির this.setStateবাইরে বলা হয়) রেস শর্ত থাকতে পারে ।

React.useEffect(() => {
  let isCancelled = false

  callApi(id).then(...).catch(...) // similar to above

  return () => (isCancelled = true)
}, [id])

এটি জাভাস্ক্রিপ্টে বন্ধ হওয়ার জন্য ধন্যবাদ কাজ করে ।

সাধারণভাবে, উপরের ধারণাটি প্রতিক্রিয়াযুক্ত ডক দ্বারা প্রস্তাবিত মেক্যান্সেবল পদ্ধতির নিকটে ছিল , যা স্পষ্টভাবে জানিয়েছে states

ইসমাউন্ট একটি অ্যান্টিপ্যাটার্ন is

ক্রেডিট

https://juliangaramendy.dev/use-promise-subscript/

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.