Dalam komponen react saya, saya mencoba menerapkan pemintal sederhana saat permintaan ajax sedang berlangsung - saya menggunakan status untuk menyimpan status pemuatan.
Untuk beberapa alasan, bagian kode di bawah ini di komponen React saya membuat kesalahan ini
Hanya dapat memperbarui komponen yang dipasang atau dipasang. Ini biasanya berarti Anda memanggil setState () pada komponen yang tidak terpasang. Ini tidak boleh dilakukan. Silakan periksa kode untuk komponen yang tidak ditentukan.
Jika saya menyingkirkan panggilan setState pertama, kesalahan akan hilang.
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 & 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>
);
}
Pertanyaannya adalah mengapa saya mendapatkan kesalahan ini ketika komponen seharusnya sudah dipasang (seperti yang dipanggil dari componentDidMount) Saya pikir aman untuk mengatur status setelah komponen dipasang?
sumber
this.state = { loading : null };
Jawaban:
Tanpa melihat fungsi render agak sulit. Meskipun sudah dapat melihat sesuatu yang harus Anda lakukan, setiap kali Anda menggunakan interval Anda harus menghapusnya saat melepas. Begitu:
componentDidMount() { this.loadInterval = setInterval(this.loadSearches, this.props.pollInterval); } componentWillUnmount () { this.loadInterval && clearInterval(this.loadInterval); this.loadInterval = false; }
Karena callback sukses dan error tersebut mungkin masih dipanggil setelah dilepas, Anda dapat menggunakan variabel interval untuk memeriksa apakah sudah terpasang.
this.loadInterval && this.setState({ loading: false });
Semoga ini bisa membantu, berikan fungsi render jika ini tidak berhasil.
Bersulang
sumber
componentWillUnmount() { clearInterval(this.loadInterval); }
Itu tidak dipanggil dari
componentDidMount
. AndacomponentDidMount
memunculkan fungsi panggilan balik yang akan dijalankan di tumpukan penangan pengatur waktu, bukan di tumpukancomponentDidMount
. Rupanya, pada saat callback Anda (this.loadSearches
) dijalankan, komponen telah dilepas.Jadi jawaban yang diterima akan melindungi Anda. Jika Anda menggunakan beberapa asynchronous API lain yang tidak memungkinkan Anda untuk membatalkan fungsi asynchronous (sudah dikirimkan ke beberapa penangan), Anda dapat melakukan hal berikut:
if (this.isMounted()) this.setState(...
Ini akan menghilangkan pesan kesalahan yang Anda laporkan dalam semua kasus meskipun rasanya seperti menyapu barang-barang di bawah permadani, terutama jika API Anda menyediakan kemampuan pembatalan (seperti
setInterval
halnya denganclearInterval
).sumber
isMounted
adalah antipattern yang disarankan facebook untuk tidak digunakan: facebook.github.io/react/blog/2015/12/16/…Bagi siapa yang membutuhkan opsi lain, metode callback atribut ref bisa menjadi solusi. Parameter handleRef adalah referensi ke elemen DOM DOM.
Untuk informasi rinci tentang ref dan 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> ) }
sumber
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() { ... } }
sumber
Untuk anak cucu,
Kesalahan ini, dalam kasus kami, terkait dengan Reflux, callbacks, redirects, dan setState. Kami mengirim setState ke callback onDone, tetapi kami juga mengirim pengalihan ke callback onSuccess. Jika berhasil, callback onSuccess kami dijalankan sebelum onDone . Ini menyebabkan pengalihan sebelum percobaan setState . Jadi kesalahannya, setState pada komponen yang tidak terpasang.
Tindakan penyimpanan refluks:
generateWorkflow: function( workflowTemplate, trackingNumber, done, onSuccess, onFail) {...
Hubungi sebelum perbaikan:
Actions.generateWorkflow( values.workflowTemplate, values.number, this.setLoading.bind(this, false), this.successRedirect );
Telepon setelah perbaikan:
Actions.generateWorkflow( values.workflowTemplate, values.number, null, this.successRedirect, this.setLoading.bind(this, false) );
Lebih
Dalam beberapa kasus, karena isMounted dari React adalah "deprecated / anti-pattern", kami telah mengadopsi penggunaan variabel _mounted dan memantaunya sendiri.
sumber
Bagikan solusi yang diaktifkan oleh kait reaksi .
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) }, [])
solusi yang sama dapat diperpanjang kapan pun Anda ingin membatalkan permintaan sebelumnya pada perubahan id pengambilan, jika tidak, akan ada kondisi balapan di antara beberapa permintaan dalam penerbangan (
this.setState
disebut rusak).React.useEffect(() => { let isCancelled = false callApi(id).then(...).catch(...) // similar to above return () => (isCancelled = true) }, [id])
ini bekerja berkat penutupan javascript.
Secara umum, ide di atas mendekati pendekatan makeCancelable yang direkomendasikan oleh react doc, yang dengan jelas menyatakan
Kredit
https://juliangaramendy.dev/use-promise-subscription/
sumber