해당 주제로 유트브에 영상을 올렸습니다! 체키라웃. 완전쉬움 https://youtu.be/Z_eWhLpnhbk
결론: 콜백은 괜히 콜백이 아니다~!
사건의 발단
useState를 배우며 Lazy initialization이라는 개념이 나왔다. 근데 당최 뭔 소리인지 이해가 되지 않았다. 콜백을 사용하면 초깃값을 한번만 실행해서 좋다는건 알겠는데... 왜 그런건지가 명확히 이해가 안되었다. 그래서 내가 이해하려고 정리해봤다. 사실 이해하니까 별거아니다!
useState Lazy initialization
만약 함수컴포넌트 안 아무데나 'console.log'를 넣는다면 이후에 화면이 재렌더링되는 어떤 일을 할 때마다(버튼을 클릭했다 치자) 콘솔로그가 출력되는 것을 발견할 수 있다. 이는 당연한 결과인데, 버튼을 눌러서 state를 변경할 때마다 랜더링을 일으키고 그 버튼을 담고있는 함수 컴포넌트 자체가 랜더링되기 때문이다.
여기서 중요한 점!
함수 컴포넌트가 랜더링된다는건 그 안에있는 코드들도 싹~다 랜더링이 된다는거다(useEffect와 같은 훅으로 그걸 막지 않는이상). 다시 말하자면 랜더링이 될 때마다 함수가 담고있는 우리가 만들어놓은 모든 변수나 인자값들이 새로 만들어지고 값이 평가된다는거다. 앞서 콘솔로그가 계속 찍히는 이유다. 보통 경우에는 큰일이 아닌데, 자바스크립트는 그정도쯤이야~ 커버가 가능할정도로 빠르고 알아서 최적화를 잘 하기 때문이다. 그래서 애초에 우리가 고정값을 정해놓고 쓰는 초기값같은건 신경쓰지 않아도 된다. 평소에 숫자로도 초기값 많이 지정해놓죠?
이런거 말이에유~
const initialState = 0
const [count, setCount] = React.useState(initialState)
그런데 만약에 초기값이 무겁고 비용을 많이 차지하는 경우라면 어떨까?
const initialState = calculateSomethingExpensive(props)
const [count, setCount] = React.useState(initialState)
더 실용적으로는, 초기값으로 localStorage를 읽어서 값을 가져와야하는 경우라면?(입출력 계산이 필요한 경우)
const initialState = Number(window.localStorage.getItem('count'))
const [count, setCount] = React.useState(initialState)
여기서 생각해보자!
React가 우리가 설정해놓은 초기값을 필요로 하는 순간은 맨 처음 화면이 랜더링 된 단 한번 뿐이다🧐 (이후에는 변경된 state값을 넣어주니까) 그런데 앞서 말했듯이 어떠한 이유로 랜더링이 일어날 때마다 이 localStorage에서 값을 가져오는 초기화작업도 다시 진행된다. 그 값이 사용되거나 필요하지 않더라도 말이다.
그래서, Lazy initialization
초기값에 값, 함수 자체가 아니라 콜백함수를 넣어주면 이 문제는 간단하게 해결된다.
const getInitialState = () => Number(window.localStorage.getItem('count'))
const [count, setCount] = React.useState(getInitialState)
함수를 만드는건 빠르다. 그 안에 아무리 비용이 많이 들어가는 작업이 들어있다 해도, 그 작업은 오로지 우리가 그 함수를 호출할 때에만! 일어난다. (필요할 때 순차적으로 실행을 일으키기 위해 쓰는게 콜백함수가 아니던가?) 이제 React는 초기값이 필요할 때에만, 즉 최초로 컴포넌트가 랜더링 될 때에만 콜백함수를 호출하게 된다. 항상 바쁘게 랜더링이 일어나는게 아니라 필요할 때만 한번씩 나오기 때문에 '게으른'이라는 말이 붙은거다.
lazy initialization은 결국 성능 최적화작업이다. 문서에서는 '비싼 비용의 계산' 이 필요할 때 쓰라고 되어있다. 항상 사용하는건 아니지만 유용하게 쓸 수 있는 상황이 있을거다. 앞선 예처럼 localStorage의 접근, map, filter, find등의 배열을 조작하는것들, new Date()등이 될 수 있다. 그러니 이런것이 있다는걸 인식하고 필요할 때 사용할 수 있으면 베스트다.
참고자료
https://kentcdodds.com/blog/use-state-lazy-initialization-and-function-updates
useState lazy initialization and function updates
When to pass a function to useState and setState
kentcdodds.com
원리를 이해하는건 항상 짜릿해~
'Front-End Developer > React' 카테고리의 다른 글
styled-components 사용시 Invalid hook call 오류 해결하기 (2) | 2022.07.03 |
---|---|
리액트 유치원이 개원했습니다. (유투브 채널개설) (0) | 2022.06.20 |
useCallback. [의존성 배열] 난 너만 바라봐 (0) | 2022.06.15 |
Router v6 헷갈려서 공부해봤다. 기초정리 (0) | 2022.06.14 |
React를 한다면 무조건 알아야 할 - useRef 1편 (0) | 2022.06.13 |