8월 5일 강의를 이해한 대로 정리한 글입니다.
틀린 내용이 있으면 지적해 주세요 !
많이 해봤자 0.001초 개선되기 때문에 정말 중요한 건 아닙니다. 하지만 D3.js, 핀테크와 같이 성능이 중요한 회사는 필요합니다.
하지만 아는 것과 모르는 것은 다르기 때문에 알고 갈 필요는 있습니다.
리액트 최적화를 처음부터 하려다 보면 효율을 생각해야 하기 때문에 오히려 코드의 가독성이 떨어질 수 있습니다. 따라서 처음부터 최적화를 진행하지 않고 제품의 서비스가 너무 느리다 싶을 때 해도 늦지 않습니다.
리렌더링 막는 방법 4가지
input, output이 똑같다면, 그대로 다시 쓸 수 있게 하는 기법
기본적으로 컴포넌트의 리렌더링은 state나 props가 변할 때 일어납니다. 하지만 자식 컴포넌트의 state나 props가 변하지 않았는데, 부모 컴포넌트의 state, props가 변해 리렌더링 된다면, 자식 컴포넌트 또한 리렌더링 됩니다. 이것을 막기 위해 Memoiztaion
기법을 사용합니다.
Memoiztaion
기법을 사용하는 방법으론 React.PureComponent
(클래스형)과 React.memo
(함수형) 두 가지가 있습니다. 같은 props 인데 리렌더링이 자주 일어날 것 같은 컴포넌트에 적용하면 됩니다.
// 클래스형
class CounterButton extends React.PureComponent { ... }
// 함수형
const CounterButton = ({ color }) => { ... }
export default React.memo(CounterButton);
useMemo
는 memoizing
된 값을 return 하는 hook입니다. 즉 컴포넌트 내부에서 발생하는 연산을 최적화할 수 있습니다. 함수와 의존 값을 받아와 의존 값이 달라질 때만 재연산을 합니다.
// utils/getSum.js
const getSum = (numbers) => {
return numbers.reducer((a, b) => a + b);
};
// 컴포넌트
const Sum = () => {
const arr = [1, 2, 3, 4];
// arr이 변하지 않는 이상 재연산을 하지 않는다.
const value = useMemo(() => getSum(arr), [arr]);
};
불변성이 지켜지지 않는다면 객체/배열의 값이 새로워져도 바뀐 것을 감지할 수 없습니다. 즉, 불변성을 지켜야 하는 이유는 이전 Virtual DOM에 있던 내용과 현재 내용을 빠르게 비교해 바뀐 DOM만 실제 DOM에 적용하기 위함입니다.
기존의 값을 직접 수정하지 않으면서 새로운 값을 만들어 낸다.
// 기존의 words의 복사 본에, 'marklar'를 추가합니다.
(O) : words: [...state.words, 'marklar']
// 기존의 words에 marklar를 추가합니다.
(X): words: state.words.concat(['marklar'])
// colormap을 그대로 가져오고 교체할 부분만 교체
(O) return Object.assign({}, colormap, { right: "blue" });
// 객체에 바로 접근하여 교체
(X) olormap.right = "blue";
// colormap 복사 본, 교체할 부분만 교체
(O) return {...colormap, right: 'blue'};
Javascript 참조형의 특징
배열
, 객체
, 함수
와 같은 타입은 값을 저장할 때 다른 곳에 저장하고 메모리 주소(참조 값)만을 가지고 있습니다. 따라서 직접 값을 바꾸려는 경우 참조 값만 변할 뿐,
원본 값은 변하지 않습니다.
참조형의 특징으로 인해 리렌더링 되는 상황 막기
useCallback
hook을 사용합니다. useCallback
은 함수의 이전 값을 기억하고 있어 함수 리렌더링을 막을 수 있습니다. 두 번째 인자에 의존성 값을 넣어 조절할 수 있싑니다.const clickHandler = useCallback(() => {
alert("clicked!");
}, []);
// 올바른 방법
const MENU_ITMM = {
name: "About",
link: "/about",
};
function TopBanner() {
return <MenuList menu={MENU_ITEM} />;
}
// 올바르지 않은 방법
function TopBanner() {
return <MenuList menu={{ name: "About", link: "/about" }} />;
}
useEffect
hook은 두 번째 인자에 의존성 배열을 설정함으로써 리렌더링 되는 조건을 설정할 수 있습니다. 하지만 의존성 배열이 너무 길다면, 오히려 성능에 악영향을 끼칠 수 있습니다. 따라서 줄일 수 있다면 최대한 줄이는 것이 좋습니다.
const [toggle, setToggle] = useState(false);
useEffect(() => {
setToggle(!toggle);
}, [toggle]);
다음과 같은 방법으로 줄일 수 있습니다.
useEffect(() => {
setToggle((prev) => !prev);
}, []);