React.memo
는 props의 얕은 비교를 통해 자식 컴포넌트가 받을 props가 이전과 동일한 경우, 자식 컴포넌트의 리렌더링을 방지한다.
const Parent = () => {
const arr = [1, 2, 3]; // 매번 새로운 배열 생성
return <Child data={arr} />;
};
const Child = React.memo(({ data }) => {
console.log("Child re-rendered");
return <div>{data.join(", ")}</div>;
});
useMemo
로 참조값 고정하기const Parent = () => {
const arr = useMemo(() => [1, 2, 3], []); // 동일 참조 유지
return <Child data={arr} />;
};
const Parent = () => {
const handleClick = () => console.log("Clicked");
return <Child onClick={handleClick} />;
};
const Child = React.memo(({ onClick }) => {
console.log("Child re-rendered");
return <button onClick={onClick}>Click me</button>;
});
useCallback
으로 참조값 고정하기const Parent = () => {
const handleClick = useCallback(() => console.log("Clicked"), []);
return <Child onClick={handleClick} />;
};
const MyContext = React.createContext();
const Parent = () => {
const value = { name: "John" };
return (
<MyContext.Provider value={value}>
<Child />
</MyContext.Provider>
);
};
const Child = React.memo(() => {
const contextValue = useContext(MyContext);
console.log("Child re-rendered");
return <div>{contextValue.name}</div>;
});
최적화 방법은 Context 값을 최소한의 책임으로 나누거나, useMemo
로 Context 값의 참조를 고정해야 한다.
이미지 크기나 용량, 지연 시간 등 프로젝트를 하면서 직접 적용했던 최적화 방법을 소개하고자 합니다.
Google은 온라인 이미지의 크기를 줄이기 위해 WebP 파일 포맷을 개발했습니다. 사진과 그래픽의 크기를 줄여 웹사이트가 빨리 로드되도록 할 수 있는데요. JPEG를 대체하기 위해 제시되었습니다.
웹사이트의 트래픽 감소 및 로딩 시간 단축을 목적으로, 사진 이미지 압축 효과가 높은 것으로 알려져 있습니다.
<img
src="/pop_singer4.webp"
loading="lazy"
alt="Camila Cabello"
/>
여느 확장자와 같이 .webp
로 이미지를 불러올 수 있습니다.
img태그의 loading="lazy"
속성은 이미지가 화면에 보이기 전까지 로딩되지 않도록 합니다. 사용자가 스크롤하여 이미지를 볼 위치에 도달하면, 그때 이미지를 로드하기 때문에 초기 페이지 로딩 속도를 개선할 수 있습니다.
저는 여러 이미지가 들어가는 페이지를 제작해야 했었고 아래의 방법으로 구현하였습니다.
import React from 'react';
const LazyImage = ({ src, alt, ...props }) => {
return <img src={src} alt={alt} loading="lazy" {...props} />;
};
export default LazyImage;
img태그를 가져와 무조건 loading="lazy
로 적용하는 컴포넌트를 만들었습니다.
<LazyImage
src="/pop_singer4.webp"
loading="lazy"
alt="Camila Cabello"
/>
img태그 대신 LazyImage
로 지연 로딩을 적용하였습니다. 지연 로딩뿐만 아니라 다른 속성들도 컴포넌트로 묶어 사용해봐도 좋을 것 같네요.
프로젝트에서 음악을 재생해야 할 때가 있었는데 제공받은 wav
확장자를 가진 파일이 로컬에서는 지연없이 잘 재생되었다. 하지만 배포사이트에서 2~3초 지연되고 재생되는 문제가 생겼다. 확장자를 mp3
로 바꾸니 1초 이내로 지연이 줄어듦은 확인할 수 있었다.
또한, 기존 용량은 5MB이었으나 확장자를 바꾸고 용량이 줄어듦을 확인할 수 있었다.
audio태그에는 preload
라는 속성이 존재한다. 해당 속성을 none
로 설정한다면 사용자가 클릭할 시 음악 파일이 로드된다.
따로 속성을 설정해주지 않는다면 preload
의 기본값이 auto
가 된다. 이것은 컴포넌트 마운트 시 오디오를 미리 로드하게 되어, 당장 필요없는 음악 파일까지 모두 로드하게 된다.
적용한 코드
<audio
preload="none"
ref={(el) => (audioRefs.current[item.audio] = el)}
/>
제대로 사용해보지 못한 useMemo나 useCallback을 새로 알 수 있게 되었습니다. 리액트 공식문서에도 다양한 사용법이 있어 제대로 공부해보려 합니다.
추가로 프로젝트를 하면서 적용했던 이미지, 오디오 최적화 방법을 정리해봤습니다. 최적화 전의 웹사이트 성능을 측정하지 않아 정확한 지표를 보여주지 못함에 아쉬움이 남네요. 기록의 필요성을 느꼈던 이번 포스트였습니다.