useInterval.js 커스텀 훅에서, 왜 첫번째 useEffect를 계속 반복해야할까요?
462
3 asked
안녕하세요 제로초님. 리액트 강의 언제나 잘 듣고 있습니다. 양질의 강의 너무 감사합니다. 제로토님의 '커스텀 훅으로 우아하게 인터벌하기' 강의를 듣고 난 후 개인적으로 코드를 분석해보고 있었는데, 공식 문서도 찾아보고 개인적으로 테스트를 굴려봐도 해결되지 않는 의문이 있어 찾아왔습니다. 먼저, 함수 컴포넌트 파일에서 아래 <1번> 처럼 구성하였기 때문에, 변수 changeHand에는 모양만 같을 뿐 저장공간이 다른 새로운 함수가 매 랜더링 시 마다 만들어진 후 useInterval에 매개변수로 넘어가겠구나.. 하고 이해했습니다. <1번> const changeHand = () => {
console.log(imgCoord);
if (imgCoord===rspCoords.r) {
setImgCoord(rspCoords.s);
} else if (imgCoord === rspCoords.s) {
setImgCoord(rspCoords.p);
} else if (imgCoord === rspCoords.p) {
setImgCoord(rspCoords.r);
}
}
useInterval(changeHand, isRunning ? 100 : null); 그리고 useInterval 함수와 아래 <2번> 코드가 컴포넌트가 새로 랜더링 될 때 마다 실행 될 것이라고도 이해했습니다. <2번> useEffect(()=>{
savedCallback.current = callback;
}); 그러니 즉, 아래 두 코드를 해석해보자면 매 랜더링 시 마다 새로운 changeHand 함수를 만들어, useInterval을 호출해 매개변수로 넘겨준 다음 useRef 훅으로 saveCallback.current에 저장해주고 있다.. 라고 이해했습니다. (잘 이해한게... 맞을까요..?) 그리고 이렇게 저장된 changeHand 함수는 <3번> 코드의 setInterval(tick, delay)에 의해, delay초 마다 한번씩 실행되게 된다는 내용 까지 이해했습니다. <3번> useEffect(()=>{
function tick() {
savedCallback.current();
}
if (delay !== null) {
let id = setInterval(tick, delay);
return () => { clearInterval(id);}
}
}, [delay]); 일단 저는 '왜 첫번째 useEffect(2번 코드)를 계속 반복해야할까요?' 라는 질문의 답에 대해서, 매 랜더링 시 마다 컴포넌트와 컴포넌트 함수들은 새로이 만들어지기 때문에, 마찬가지로 savedCallback에도 이전 함수가 아니라 새로 만들어진 함수를 저장해야하기 때문이겠구나.. 라고 생각했었습니다. 하지만 이 가정이 맞다면, 컴포넌트가 재실행되며 이전 컴포넌트 객체였던 것은 생명주기 순서에 따라 새로 랜더링 되기 전에 삭제될 테니, 이전 컴포넌트 객체와 함수들은 저장공간에 남아있지 말아야 할 것입니다. 그래서 별도로 배열 변수를 만들어, 랜더링 시 마다 만들어지는 changeHand 함수를 순서대로 저장한 후 한 20번 째 랜더링 쯤에서 두 번째로 만들어진 changeHand 함수를 콘솔창에 찍어봤었습니다. 저는 이 과정을 통해 undefind 에러가 발생하거나 null값이 출력될 줄 알았는데(더이상 메모리에 없는 함수 객체일테니..) 잘만 실행되더군요 ㅠㅠㅠ 제가 어떤 부분을 이해하지 못하고 있는 걸까요..? (아예 통째로 잘못 이해하고 있는 것도 같고... ㅠㅠ) 감사합니다.
Answer 2
1
질문 줄바꿈 다시 해주시면 안 될까요? 읽을수가없네요 ㅠㅠ
2
지나가다 포맷팅 해드렸습니다. ㅎ
안녕하세요, 제로초 님.
리액트 강의 언제나 잘 듣고 있습니다. 양질의 강의 너무 감사합니다.
제로초 님의 "커스텀 훅으로 우아하게 인터벌하기" 강의를 듣고 난 후, 개인적으로 코드를 분석해 보고 있었는데, 공식 문서도 찾아보고 개인적으로 테스트를 굴려봐도 해결되지 않는 의문이 있어 찾아왔습니다.
먼저, 함수 컴포넌트 파일에서 아래 <1번>처럼 구성하였기 때문에, 변수 changeHand에는 모양만 같을 뿐 저장공간이 다른 새로운 함수가 렌더링 될 때마다 만들어진 후 useInterval에 인자로 넘어가겠구나... 하고, 이해했습니다.
// <1번>
const changeHand = () => {
console.log(imgCoord)
if (imgCoord === rspCoords.r) {
setImgCoord(rspCoords.s)
} else if (imgCoord === rspCoords.s) {
setImgCoord(rspCoords.p)
} else if (imgCoord === rspCoords.p) {
setImgCoord(rspCoords.r)
}
}
useInterval(changeHand, isRunning ? 100 : null)그리고 useInterval 함수와 아래 <2번> 코드가 컴포넌트가 새로 렌더링 될 때마다 실행될 것이라고도 이해했습니다.
// <2번>
useEffect(() => {
savedCallback.current = callback
})그러니 즉, 아래 두 코드를 해석해 보자면 렌더링 될 때마다 새로운 changeHand 함수를 만들어, useInterval을 호출해 매개변수로 넘겨준 다음 useRef 훅으로 saveCallback.current에 저장해주고 있다... 라고 이해했습니다. (잘 이해한게... 맞을까요...?)
그리고 이렇게 저장된 changeHand 함수는 <3번> 코드의 setInterval(tick, delay)에 의해, delay초 마다 한 번씩 실행되게 된다는 내용까지 이해했습니다.
// <3번>
useEffect(() => {
function tick() {
savedCallback.current()
}
if (delay !== null) {
let id = setInterval(tick, delay)
return () => {
clearInterval(id)
}
}
}, [delay])일단 저는 "왜 첫 번째 useEffect(2번 코드)를 계속 반복해야 할까요?"라는 질문의 답에 대해서, 렌더링 될 때마다 컴포넌트와 컴포넌트 내부의 함수들은 새로 만들어지기 때문에, 마찬가지로 savedCallback에도 이전 함수가 아니라 새로 만들어진 함수를 저장해야 하기 때문이겠구나... 라고 생각했었습니다.
하지만 이 가정이 맞는다면, 컴포넌트가 재실행되며 이전 컴포넌트 객체였던 것은 생명주기 순서에 따라 새로 렌더링 되기 전에 삭제될 테니, 이전 컴포넌트 객체와 함수들은 저장공간에 남아있지 말아야 할 것입니다.
그래서 별도로 배열 변수를 만들어, 렌더링 될 때마다 만들어지는 changeHand 함수를 순서대로 저장한 후 한 20번째 렌더링 쯤에서 두 번째로 만들어진 changeHand 함수를 콘솔에 찍어봤었습니다. 저는 이 과정을 통해 undefined 에러가 발생하거나 null 값이 출력될 줄 알았는데(더 이상 메모리에 없는 함수 객체일 테니...) 잘만 실행되더군요. ㅠㅠ
제가 어떤 부분을 이해하지 못하고 있는 걸까요...? (아예 통째로 잘못 이해하고 있는 것도 같고... ㅠㅠ)
감사합니다.
0
아. 참조가 남아있다면 객체와 함수도 계속 남아있는군요. 그 사실을 몰랐네요... 머쓱.. 넘 감사합니다. 그리고 질문글 가독성이 완전 엉망인 것도 모르고 있었네요 byn님 포맷팅 너무 감사합니다.
두분 다 즐거운 하루 되세요..!
npm run dev 실행 시 포트가 안뜨는 문제
0
202
2
timeouts.current를 useEffect 의 input값으로 넣었을때
0
85
2
렌더링 테스트 코드 (Hooks)
0
80
1
Cannot find package 'react-refesh' 이런 에러 뜨시는 분들 보세요.
0
149
1
해당 에러 뜨는 분들 보세요. "Uncaught TypeError: ReactDom.createRoot is not a function"
1
191
1
강사님 레포지토리에서 코드 복사 시 master 브랜치 말고 react18 브랜치꺼 복붙하세요ㅠㅠ
0
95
1
useMemo와 useCallback 사용 시기
0
205
2
onRightClickTd가 작동을 하지 않습니다.
0
226
1
action.type 불러오는 방식
0
222
2
onClickRedo 질문
0
172
1
const Try = require(./Try) 빨간줄
0
248
1
npx webpack 실행시
0
313
1
지뢰찾기 강좌에서 빈칸들 한번에 열기 파트에서 여쭤보고싶은부분이 있어서 글 올립니다.
0
234
1
강좌에서 다루지 않은 기능들은 어떻게 학습하면 좋을까요?
0
311
1
react devtool이 enable 않됩니다.
0
530
2
React 랜더링이 되지 않습니다.
0
409
2
비동기로 동작하는 setState에 대해서
0
331
1
npm run dev 할 때 에러발생
0
478
2
memo, PureComponenet, shouldComponentUpdate 관련 질문
0
206
1
devMiddleware의 필요성
0
352
1
리액트에서 화살표 함수를 사용해야하는 이유
0
931
2
path.join관련질문
0
280
2
2-9. 웹팩 데브 서버와 핫 리로딩 설치과정 시 에러
0
371
1
next.js 에서 이와 비슷한 예제를 돌리고있는데 react랑 달라서 질문 드립니
1
488
4

