javascript - React-setState() على مكون غير مثبت




ajax reactjs (4)

في مكون التفاعل الخاص بي ، أحاول تنفيذ أداة تدحرج بسيطة بينما طلب ajax قيد التقدم - استخدم الحالة لتخزين حالة التحميل.

لسبب ما ، يلقي هذا الجزء من الكود أدناه في مكون React الخاص بي هذا الخطأ

يمكن فقط تحديث مكون مثبت أو متصاعد. هذا يعني عادةً أنك اتصلت بـ setState () على مكون غير مركب. هذا هو عدم المرجع. يرجى التحقق من رمز المكون غير المحدد.

إذا تخلصت من أول اتصال setState ، فسيختفي الخطأ.

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

السؤال هو لماذا أتلقى هذا الخطأ عندما يجب أن يتم تثبيت المكون بالفعل (كما يتم استدعاؤه من componentDidMount) اعتقدت أنه كان من الآمن ضبط الحالة بمجرد تركيب المكون؟


السؤال هو لماذا أتلقى هذا الخطأ عندما يجب أن يتم تثبيت المكون بالفعل (كما يتم استدعاؤه من componentDidMount) اعتقدت أنه كان من الآمن ضبط الحالة بمجرد تركيب المكون؟

لا يتم استدعاء من componentDidMount . componentDidMount الخاص بك يولد وظيفة رد الاتصال التي سيتم تنفيذها في مكدس معالج مؤقت ، وليس في مكدس مكوندومونت. على ما يبدو ، بحلول الوقت الذي يتم فيه تنفيذ رد الاتصال ( this.loadSearches ) ، تم إلغاء تثبيت المكون.

لذا فإن الإجابة المقبولة ستحميك. إذا كنت تستخدم بعض واجهات برمجة التطبيقات غير المتزامنة الأخرى التي لا تسمح لك بإلغاء الوظائف غير المتزامنة (المقدمة بالفعل إلى بعض المعالج) ، فيمكنك القيام بما يلي:

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

سيؤدي ذلك إلى التخلص من رسالة الخطأ التي تبلغ عنها في جميع الحالات ، على الرغم من أنها تبدو وكأنها تجتاح الأشياء تحت السجادة ، خاصة إذا كانت واجهة برمجة التطبيقات توفر إمكانية إلغاء (كما يفعل setInterval مع clearInterval ).


دون رؤية وظيفة التقديم صعبة بعض الشيء. على الرغم من أنه بإمكانك بالفعل اكتشاف شيء ما يجب عليك فعله ، إلا أنه في كل مرة تستخدم فيها فاصلًا ، يجب عليك مسحه عند إلغاء التحميل. وبالتالي:

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

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

نظرًا لأنه قد لا يزال يتم استدعاء عمليات الاستعادة للنجاح والخطأ بعد إلغاء التثبيت ، يمكنك استخدام متغير الفاصل الزمني للتحقق مما إذا كان يتم تثبيته.

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

آمل أن يساعد هذا ، توفير وظيفة التقديم إذا كان هذا لا يؤدي المهمة.

في صحتك


لمن يحتاج إلى خيار آخر ، يمكن أن تكون طريقة رد الاتصال الخاصة بسمة ref هي الحل. معلمة handleRef هي المرجع لعنصر DOM.

للحصول على معلومات مفصلة حول الحكام و DOM: 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>
 )
}

مشاركة حل مُمكّن من خلال ربط السنانير

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

هذا يعمل بفضل closures في جافا سكريبت.

بشكل عام ، كانت الفكرة المذكورة أعلاه قريبة من نهج makeCancelable الذي أوصت به وثيقة التفاعل ، والتي تنص بوضوح

isMounted هو أنتيباترن

ائتمان

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





state