useEffect
이때, useEffect
를 사용해서 코드를 다음처럼 수정하면 이벤트 리스너가 최초 렌더 시 한 번만 생성된다.
만약, 의존성 배열로 [value]
를 주면 value
에 값이 들어갈 때마다 이벤트 리스너가 생성된다.
import React, {useState, useEffect} from 'react'
export default function Ex1() {
const [value, setValue] = useState('');
useEffect(() => {
document.addEventListener('click', () => {
alert(1);
})
}, [])
console.log("컴포넌트 리렌더. 현재 스테이트: ", value);
return (
<input type="number" value={value} onChange={(e)=>{setValue(e.target.value)}} />
)
}
🤔 Mount, Unmount
- Mount: DOM 트리에 올라간 것
- Unmount: 아예 DOM 트리에서 사라진 것
로그인 누르면<User />
Mount
로그아웃 누르면<User />
Unmount
[]
: Mount 됐을 때 최초 1회 실행[value]
: value
가 바뀔 때마다 실행값이 바뀌는 것들을 의존성 배열에 넣을 수 있다. (prop
이나 state
) ref
같은 경우에는 값이 변경된다는 개념이 아니므로 넣지 않는다.
다음 코드에서 value
에 값을 넣어도(input
에 값을 입력해도) 초기에 들어있던 값(''
)이 alert에 나오게 된다.
useEffect
안에서 state를 사용하고 싶다면 의존성 배열로 [value]
주어야 한다. value
가 변경될 때마다 실행되도록!
그런데 바뀐 value
에 대해서 사용하고 싶어서 의존성 배열을 [value]
로 주었는데, 이렇게 하면 value
가 바뀔 때마다 이벤트 리스너가 생성돼서 쌓인다.
'123'을 입력했을 때
- 기대한 결과: alert 1번 나타나기 (123)
- 실제 결과: alert 4번 나타나기 (초기값 -> 1 -> 2 -> 3)
❗ 이때 필요한 것이 clean up이다.
최초로 한 번 렌더된 이후, 리렌더링 될 때
1. return문이 먼저 실행된다.
2. 그리고 바뀐 값에 대해 useEffect
가 실행돼서 이벤트 리스너가 등록되는 것이다.
🤔 왜 제일 처음 실행됐을 땐 return문이 실행되지 않을까?
useEffect
는 clean up 함수를 잘 들고 있다가value
가 바뀌었을 때 실행한다.
그래서 최초로 렌더되었을 때는 clean up 함수가 실행되지 않는 것이다.
setTimeout()
, clearTimeout()
이용import React, {useState, useEffect} from 'react'
export default function Ex1() {
const [value, setValue] = useState('');
useEffect(() => {
let timer;
if (value){
timer = setTimeout(() => {
console.log(value);
}, 3000);
}
return () => {
if(timer) {
clearTimeout(timer);
}
}
}, [value]);
return (
<>
<input
type="number"
onChange={(e) => {setValue(e.target.value)}}
/>
</>
);
}
🤔 리액트가 리렌더를 하기 위해 값이 바뀌었는지 판단하는 방법?
array/object(레퍼런스 타입)의 경우, 참조하는 주소가 바뀌었을 때 값이 바뀌었다고 판단한다.
따라서 의존성 배열에 레퍼런스 타입을 넣는 경우, 변경을 감지할 수 있도록 작성해야 한다. (= 참조하는 주소가 바뀌도록 해야 한다.)
value
가 바뀌어도 1부터 2억까지 더한 값은 변하지 않으므로 저장해둔다.useMemo
useMemo
를 통해서 계산된 값을 저장할 수 있다.다음 코드는 의존성 배열이 변경되었을 때 메모이제이션을 다시 수행한다.
input
에 값이 다시 입력되면 [props.max]
가 변경되었으므로 다시 계산한다.input
에 값을 입력했을 땐 다시 계산하지 않는다.[props.max, value]
로 주면 자식 input
이 바뀌었을 때도 불필요한 계산을 하게 된다.useCallback
useMemo
의 함수 버전이다.useMemo
는 콜백함수에서 return 하는 값이 메모이제이션 되는 것useCallback
은 콜백함수 자체가 메모이제이션 되는 것🤔
- 함수를 return할 땐
useMemo
,useCallback
둘 다- 그 외엔
useMemo
현업에서 대부분의 환경에서는 Memoization을 사용하진 않으므로 그냥 정말! 필요할 때 '아 이런 게 있었지~' 라고 생각할 수 있는 정도면 OK.