Yaşam döngüsü yöntemlerini kancalara tepki verin
Makaleler içeren basit bir blogum var. Ve sınıfları işlevsel bileşenlere ve kancalara yeniden yazmak istiyorum. Şimdi bu mantığı düzenle / ekle formuyla sayfam için yaşam döngüsü yöntemlerinde aldım: iyi çalışıyor.
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;
}
Hepsini böyle kancalara yeniden yazdım:
//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();
}, []);
- Hata aldım - "Çok fazla yeniden işleme var." codeandbox tam kodunda: codesandbox
Tuhaf, ancak localhost'ta "Çok fazla yeniden işleme" hatası yok.
Sınıfımın "shouldComponentUpdate" metodunu kancalara nasıl yeniden yazacağımı bilmiyorum. "Not" u denedim, ancak bu durumda nasıl yazılacağı hakkında hiçbir fikrim yok.
Ve yine de bir şeyi kaçırıyorum çünkü hepsi işe yaramayacak - form alanlarını düzgün bir şekilde güncellemiyor.
React kancaları hakkında iyi bir bilginiz varsa lütfen yardım edin veya biraz tavsiye verin - nasıl düzeltilir?
Yanıtlar
Bağımlılık içermeyen etki neden oluyor "Too many re-renders."
: her işlemeden sonra çalışıyor, ardından setIsLoading
state ( loading
) ' yi güncellemeye çağırıyor , bu da bileşenin yeniden oluşturulmasına neden olacak, bu da effect
tekrar çalıştıracak ve tekrar setState
çağrılacak effect
ve böyle devam edecek ...
//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);
})
sorunu çözmek için ya setIsLoading
ondan kaldırın ya IsLoading
da bağımlılık olarak ekleyin .
//componentDidUpdate
useEffect(() => {
...
setIsloading(false);
},[isLoading]);
ayrıca iki bağlama efektini buna benzer şekilde birleştirebilirsiniz (sizinki de çalışıyor, ancak bunun biçimsel olarak tercih edilebilir olduğunu düşünüyorum):
//componentDidMount
useEffect(() => {
if (id) {
setIsloading(true);
return props.onLoad(userService.articles.get(id));
}
setIsloading(false);
props.onLoad(null);
//componentWillUnmount
return function () {
props.onUnload()
}
}, []);
ikinci madde için: bileşeninizin yeniden yazılması hakkında shouldComponentUpdate
; Öncelikle shouldComponentUpdate
, her zaman geri döndüğünüz true
ve sadece loading
durumu tetiklemek için kullandığınız için mevcut durumunuzun makul olmadığını belirtmeliyim; ve React.memo ile yazılmaya uygun değildir (~ shouldComponentUpdate
sınıf bileşenlerine eşdeğerdir ); bu nedenle, loading
durumu belirlemek için her props değişikliğinde çalıştırılacak bir şeye ihtiyacınız vardır props
ve bunun için bağımlılığı aşağıdaki gibi bir efekt kullanabilirsiniz :
//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
Benim farkındalığıma göre, bu işi yapacak, (ilk etapta mantığı neden bu şekilde yazdığınızı anlamakta zorlanmanıza rağmen) ve eğer iyi gitmiyorsa, mantığı ihtiyaçlarınıza uyacak şekilde biraz ayarlayabilirsiniz, sahne değişim efektinin nasıl çalıştığını düşünün. Ayrıca birçok kolu gereğini typeError
durumunda id
, params
ya da match
yok ve Opsiyonel zincirleme burada kullanışlı bir araç olabilir ->props.match?.params?.id
Eski yaşam döngüsü kancalarını kaçırırsanız, bunları her zaman özel kancalar olarak yeniden oluşturabilirsiniz:
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)
}
Kullanım (örneğiniz yeniden düzenlendi):
//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();
});