Invalid Hook call 에러가 나는 원인에는 여러가지가 있는데, Hook에 대해서 잘 모르는 상태로 썼을때 에러가 날 확률이 높아진다.
특히 커스텀 Hook을 만들어 사용할때 이런 개념들을 모르고 쓰면 코드를 짜기도 어렵지만 디버깅할 때 상당히 골치아파진다.
use*
로 시작하는 여러가지 Hook을 하나로 묶기 위해그러면 useEffect
와 useMemo
, useCallback
의 차이를 알아보고 적재적소에 활용하여 에러를 마주칠 확률을 낮춰보자.
뭔가
가 바뀌면 어떤 동작
을 자동으로 실행하기 위해 사용useEffect(() => {어떤 동작}, [뭔가]);
useState
와 함께 사용하는 예시const [ state, setState ] = useState('idle'); // 프로세스의 진행상태를 저장하는 state
useEffect(() => {
if (state === 'success'){ // state가 success일때만 if문이 실행된다.
console.log("PROCESS DONE!! <<success>>");
setState('idle'); // state를 초기상태로 돌려준다.
}
}, [state]); // 프로세스가 idle -> pending -> success/fail로 바뀔 때마다 useEffect로 감싼 부분이 실행된다.
state
는 코드는 프로세스가 진행됨에 따라 idle
, pending
, success
or fail
로 업데이트 된다. 상태가 없데이트 될때마다 useEffect
에 전달한 콜백함수가 실행이 되는데, 내부에 if
문이 있기 때문에 console.log
가 되는 것은 success
일때 뿐이다.원하는 타이밍
에 호출시킬 함수
를 만들기 위해 사용(함수가 반환됨)const [ food, setFood ] = useState('샐러드');
const [ menuAsked, setMenuAsked ] = useState(false);
useEffect(() => {
if (menuAsked === true){
printMenu();
setMenuAsked(false); // state를 초기상태로 돌려준다.
}
}, [menuAsked])
const printMenu useCallback(() => {
console.log(`[ Today's Dinner Menu : ${food} ]`);
}, [food]);
menuAsked
의 상태가 바뀔때마다 useEffect
의 인라인 콜백함수가 실행되고, menuAsked
의 상태가 true
라면 printMenu
함수가 호출된다. 코드가 실행되는 동안 food
의 상태가 바뀌지 않는다면 printMenu
함수의 내용도 바뀌지 않는다.동작 | food | menuAsked | printMenu 함수 변화 | 출력 |
---|---|---|---|---|
최초 상태 | '샐러드' | false | X | - |
setFood('고추장 삼겹살') | '고추장 삼겹살' | false | O | - |
setFood('갈치 구이') | '갈치 구이' | false | O | - |
setMenuAsked(true) | '갈치 구이' | true | X | [ Today's Dinner Menu : 갈치 구이 ] |
setMenuAsked
를 사용하면 menuAsked
의 상태는 true
가 되지만, 메뉴를 프린트 한뒤에는 다시 false
로 초기화 된다.setFood
는 printMenu
함수에만 영향을 주고 setMenuAsked
는 메뉴의 출력에만 관여한다.useCallback
은 원하는 타이밍에 실행시킬 함수를 만드는데 사용useMemo
는 원하는 값을 업데이트하기 위해 사용const person = useMemo(
() => (
<Person
name={name}
song={favoriteSong}
/>
),
[name, favoriteSong]
);
useEffect
vs useCallback
useEffect
는 어떤 값의 변화가 동작을 자동으로 불러오도록 하고 싶을때,useCallback
은 어떤 값이 변했을때 특정 동작을 값에 따라 다르게 실행시키고 싶거나 원하는 타이밍에 어떤 동작을 실행시키고 싶을때 적합하다.state
를 바라보고 있다가 effect
를 주는 것인데 이때의 effect
는 멱등성이 유지된다.
그에 비해 useCallback
은 state
에 따라 다른 동작을 하는 함수를 리턴할 수 있을므로 동작을 state
에 따라 다르게 주고 싶을때 유용하다.
useMemo
는 값을 리턴하며, 최적화에 방점이 찍힌다.
처음 React
를 공부하기 시작했을때 용도가 비슷해보이는 것이 여러개 있어 어떤 때에 무엇을 써야할 지 몰랐는데, 사용하다보니 필요한 곳을 알게되는 것 같다. useEffect
, useCallback
, useMemo
도 글로 이해하려는 것보다는 계속해서 사용해보고 예시를 많이 보는게 이해가 빠르게 될 것 같다.
useState
와 useMemo
의 사용처 비교// b와 c를 더한 값이 a가 되는 경우
const a = useMemo(() => {b + c}, [b, c]);
// useState를 쓸 수 밖에 없는 상황
const [ name, setName ] = useState('');
const [ email, setEmail ] = useState('');
(생략)
// 1. get data from server
fetch(domain).then((res) => setName(res.data.name));
(생략)
// 2. get data from user input
return (
<Form>
<label css={labelStyle} htmlFor='email'> Email </label>
<input
type='email'
id='email'
value={email}
(...)
onChange={(event) => setEmail(event.currentTarget.value)}
/>
</Form>
)
도움이 많이 되었습니다. 감사합니다!