Bereaksi metode siklus hidup ke hook
Saya memiliki blog sederhana dengan artikel. Dan saya ingin menulis ulang kelas menjadi komponen dan kait fungsional. Sekarang saya mendapatkan logika ini dalam metode siklus hidup untuk halaman saya dengan formulir edit / tambahkan: berfungsi dengan baik.
componentDidUpdate(prevProps, prevState) {
if (this.props.match.params.id !== prevProps.match.params.id) {
if (prevProps.match.params.id) {
this.props.onUnload();
}
this.id = this.props.match.params.id;
if (this.id) {
return this.props.onLoad(userService.articles.get(this.id));
}
this.props.onLoad(null);
}
this.isLoading = false;
}
componentDidMount() {
if (this.id) {
this.isLoading = true;
return this.props.onLoad(userService.articles.get(this.id));
}
this.isLoading = false;
this.props.onLoad(null);
}
componentWillUnmount() {
this.props.onUnload();
}
shouldComponentUpdate(newProps, newState) {
if (this.props.match.params.id !== newProps.match.params.id) {
this.isLoading = true;
}
return true;
}
Saya menulis ulang semuanya menjadi kait seperti itu:
//componentDidMount
useEffect(() => {
if (id) {
setIsloading(true);
return props.onLoad(userService.articles.get(id));
}
setIsloading(false);
props.onLoad(null);
}, []);
useEffect(()=> {
prevId.current = id;
}, [id]
);
//componentDidUpdate
useEffect(() => {
//const id = props.match.params.id;
if (id !== prevId.current) {
if (prevId.current) {
props.onUnload();
}
if (id) {
return props.onLoad(userService.articles.get(id));
}
props.onLoad(null);
}
setIsloading(false);
});
//componentWillUnmount
useEffect(() => {
return props.onUnload();
}, []);
- Saya mendapat kesalahan - "Terlalu banyak render ulang." di Codesandbox kode lengkap: Codesandbox
Aneh, tapi di localhost tidak ada error "Too many re-render."
Tidak tahu apa yang harus dilakukan dengan metode kelas "shouldComponentUpdate" saya bagaimana menulis ulang ke hook. Mencoba 'memo' tetapi tidak tahu bagaimana menulis dalam kasus ini.
Lagi pula saya melewatkan sesuatu, karena semuanya tidak berfungsi - tidak memperbarui bidang formulir dengan benar.
Jika Anda memiliki pengetahuan yang baik tentang react hooks, tolong bantu, atau berikan beberapa saran - bagaimana cara memperbaikinya?
Jawaban
Efek tanpa ketergantungan menyebabkan "Too many re-renders."
: ini berjalan setelah setiap render kemudian memanggil setIsLoading
untuk memperbarui state ( loading
) yang akan menyebabkan komponen dirender ulang, yang akan menjalankan effect
lagi dan setState
akan dipanggil lagi effect
dan seterusnya ...
//componentDidUpdate
useEffect(() => {
//const id = props.match.params.id;
if (id !== prevId.current) {
if (prevId.current) {
props.onUnload();
}
if (id) {
return props.onLoad(userService.articles.get(id));
}
props.onLoad(null);
}
setIsloading(false);
})
untuk memperbaiki masalah, hapus setIsLoading
dari itu, atau tambahkan IsLoading
sebagai ketergantungan.
//componentDidUpdate
useEffect(() => {
...
setIsloading(false);
},[isLoading]);
Anda juga dapat menggabungkan dua efek pemasangan menjadi satu seperti ini (milik Anda juga berfungsi, tetapi saya pikir ini lebih disukai secara gaya):
//componentDidMount
useEffect(() => {
if (id) {
setIsloading(true);
return props.onLoad(userService.articles.get(id));
}
setIsloading(false);
props.onLoad(null);
//componentWillUnmount
return function () {
props.onUnload()
}
}, []);
untuk poin kedua: tentang menulis ulang komponen Anda shouldComponentUpdate
; pertama saya harus menunjukkan bahwa keberadaan Anda shouldComponentUpdate
tidak masuk akal, karena Anda selalu kembali true
, dan Anda hanya menggunakannya untuk memicu loading
keadaan; dan tidak memenuhi syarat untuk ditulis dengan React.memo (yang ~ setara shouldComponentUpdate
dengan komponen dalam kelas); jadi Anda hanya perlu sesuatu untuk dieksekusi pada setiap perubahan props untuk menentukan loading
status dan untuk itu Anda dapat menggunakan efek props
sebagai ketergantungannya seperti ini:
//manually keeping old props id
const prevPropsId = useRef();
useEffect(() => {
if (prevPropsId.current !== props.match.params.id) {
setIsLoading(true);
}
prevPropsId.current = props.match.params.id;
}, [props.match.params.id]);
// this hook only run if `props.match.params.id` change
berdasarkan kesadaran saya ini akan melakukan pekerjaan, (meskipun kesulitan memahami mengapa Anda menulis logika dengan cara ini di tempat pertama) dan jika tidak berfungsi dengan baik Anda dapat menyesuaikan logika sedikit agar sesuai dengan kebutuhan Anda, Anda mendapatkan ide bagaimana efek perubahan alat peraga bekerja. juga banyak yang perlu Anda tangani typeError
jika berjaga-jaga id
, params
atau match
tidak ada dan rangkaian opsional dapat menjadi alat yang berguna di sini ->props.match?.params?.id
Jika Anda melewatkan pengait siklus hidup yang lama, Anda selalu dapat membuatnya kembali sebagai pengait khusus:
function useComponentDidMount(effect) {
useEffect(() => {
effect();
}, []);
}
function useComponentWillUnmount(effect) {
useEffect(() => {
return effect;
}, []);
}
function useComponentDidUpdate(effect, dependencies) {
const hasMountedRef = useRef(false);
const prevDependenciesRef = useRef(null)
useEffect(() => {
// don't run on first render, only on subsequent changes
if (!hasMountedRef.current) {
hasMountedRef.current = true;
prevDependenciesRef.current = dependencies;
return;
}
// run effect with previous dependencies, like in componentDidUpdate!
effect(...prevDependenciesRef.current || []);
prevDependenciesRef.current = dependencies;
}, dependencies)
}
Penggunaan (contoh Anda difaktorkan ulang):
//componentDidMount
useComponentDidMount(() => {
if (id) {
setIsloading(true);
props.onLoad(userService.articles.get(id));
return;
}
setIsloading(false);
props.onLoad(null);
});
//componentDidUpdate
useComponentDidUpdate((prevId) => {
if (prevId) {
props.onUnload();
}
if (id) {
props.onLoad(userService.articles.get(id));
return;
}
props.onLoad(null);
setIsloading(false);
}, [id]);
//componentWillUnmount
useComponentWillUnmount(() => {
props.onUnload();
});