후크에 대한 라이프 사이클 메소드 반응
기사가있는 간단한 블로그가 있습니다. 그리고 클래스를 기능적 구성 요소와 후크로 다시 작성하고 싶습니다. 이제 편집 / 추가 양식이있는 페이지의 수명주기 메서드에이 논리가 있습니다. 제대로 작동합니다.
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;
}
나는 모든 것을 다음과 같은 후크로 다시 썼습니다.
//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();
}, []);
- "다시 렌더링이 너무 많습니다."라는 오류가 발생했습니다. codesandbox에서 전체 코드 : codesandbox
이상하지만 localhost에는 "너무 많은 다시 렌더링"오류가 없습니다.
내 클래스 "shouldComponentUpdate"메소드로 무엇을 해야할지 모르겠다. 어떻게 그것을 후크에 다시 쓰는지. '메모'를 시도했지만이 경우 어떻게 쓰는지 모르겠습니다.
그리고 어쨌든 나는 모든 것이 작동하지 않기 때문에 무언가를 놓치고 있습니다-양식 필드를 제대로 업데이트하지 않습니다.
리 액트 훅에 대한 좋은 지식이 있다면 도움을 주거나 조언을 해주시기 바랍니다. 어떻게 고칠 수 있을까요?
답변
종속성이없는 효과가 발생합니다 "Too many re-renders."
. 렌더링 할 때마다 실행 된 다음 setIsLoading
state ( loading
) 를 업데이트 하여 구성 요소가 다시 렌더링되도록하여 effect
다시 실행되고는 다시 setState
호출됩니다 effect
.
//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);
})
문제를 해결하려면를 제거 setIsLoading
하거나 IsLoading
종속성으로 추가하십시오 .
//componentDidUpdate
useEffect(() => {
...
setIsloading(false);
},[isLoading]);
두 개의 마운트 효과를 다음과 같이 하나로 병합 할 수도 있습니다 (귀하의 효과도 작동하지만 스타일이 더 바람직하다고 생각합니다).
//componentDidMount
useEffect(() => {
if (id) {
setIsloading(true);
return props.onLoad(userService.articles.get(id));
}
setIsloading(false);
props.onLoad(null);
//componentWillUnmount
return function () {
props.onUnload()
}
}, []);
두 번째 글 머리 기호 : 컴포넌트의 재 작성에 관하여 shouldComponentUpdate
; 먼저 나는 shouldComponentUpdate
당신이 항상 반환 true
하고 loading
상태 를 트리거하는 데에만 사용하고 있기 때문에 기존의 것이 합리적이지 않다는 것을 지적해야합니다 . 그리고 React.memo 로 작성할 자격이 없습니다 (~ shouldComponentUpdate
클래스 구성 요소 와 동등 함 ). 따라서 loading
상태 를 결정하기 위해 모든 소품 변경에 대해 실행해야하는 작업 만 있으면 되며이를 위해 다음과 props
같은 종속성으로 효과를 사용할 수 있습니다 .
//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
내 깨달음에 따라 이것이 일을 할 것입니다. (처음에 왜 이런 식으로 논리를 작성하는지 이해하는 데 어려움이 있음에도 불구하고) 제대로 작동하지 않으면 필요에 맞게 논리를 약간 조정할 수 있습니다. 소품 변경 효과가 어떻게 작동하는지 알 수 있습니다. 또한 많은 처리해야 typeError
경우 id
, params
또는 match
존재하지 않고 옵션 체인은 여기에 편리한 도구가 될 수 있습니다 ->props.match?.params?.id
이전 수명주기 후크를 놓친 경우 언제든지 사용자 지정 후크로 다시 만들 수 있습니다.
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)
}
사용법 (리팩터링 된 예제) :
//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();
});