우선 멘토님의 코드를 살펴보자.
const AdminPage = () => {
const [items, setItems] = useState(null); //모든 페이지서 알아야하는 정보는 아니기 떄문에 recoil이 아닌 useState 사용
const ref = useRef(false);
//유저아이템이 fetch되었는지 여부를 나타내는 값이다.
//값이 바뀌어도 리렌더링되지 않고, 리렌더링되어도 값을 기억한다.
const fetchUserItems = useCallback(async () => { //useCallback으로 최적화
const userItems = await getItems(); //비동기
if (userItems !== null) setItems(userItems); //추가된 아이템이 없으면 실행되지 않는다.
ref.current = true;
}, []);
useEffect(() => {
if (!ref.current) fetchUserItems(); //초기 렌더링시에 무조건 실행되는 함수.
}, []);
return (
<div>
<ItemList items={items} /> //null 혹은 item 값을 전달하고있다.
</div>
);
};
우선 리렌더링은 state값이 수정되었을때 발생한다. useRef는 값이 바뀌어도 리렌더링되지 않는다. ref는 일반 자바스크립트 객체라 react가 변경여부에 관심을 두지 않는다. useRef로 cur 값이 true로 바뀌었을 때는 유저아이템이 널이 아니어서 아이템이 state값으로 세팅되었을때이다.
1. 초기 렌더링시에(useEffect(()=>{}, [빈배열])이기때문에 초기 렌더링시에만 실행) ref값이 false이기 때문에 유저아이템을 fetch한다.
2. 유저아이템이 존재한다면 useState값을 세팅한다. 이때 state가 변경되었으니 리렌더링이 일어날 것이다.
3. 그리고 ref값도 true로 할당한다.
- 참조 콘텐츠 재생성 방지
이 부분이 위 코드와 유사해보인다.
function Video() {
const playerRef = useRef(new VideoPlayer());
// ... 위에서는 모든 렌더링에서 함수를 호출한다.
function Video() {
const playerRef = useRef(null); //null일때만 생성한다.
if (playerRef.current === null) {
playerRef.current = new VideoPlayer();
}
useCallback, useRef, 모두 최적화를 위해 사용한다. 이론적으로는 알고있었지만 사용해본 적 없고(아직) 특히 useRef를 저렇게 변수로 쓰는 것은 생각도 못했다. 앞으로 정말 유용하게 써먹을 수 있을 것 같은 팁이다. 굿.
강의중에는 무심코 흘리는 줄이 많았는데 코드 한줄한줄 뜯는 재미가 있다. 효율적이어보이고 멋있어보이는 코드라도 봤을때 이해하기엔 시간이 좀 걸리는 일이 많은데 그냥 죽죽 읽힌다. 이렇게 좋은 퀄리티라니... 역시bb 대단하다...