useMemo
hook을 사용하여 복잡하게 계산된 값을 재사용할 수 있다. useMemo로 저장된 값은 두번째 인자로 받은 deps 배열의 값의 변화가 없는 이상, 컴포넌트가 재렌더링될 때에도 다시 값을 계산하지 않는다.function sum(n: number) {
console.log('Start');
let result = 0;
for (let i = 0; i <= n; i += 1) {
result += i;
}
console.log('Finish');
return result;
}
export const Box = ({ label, n }: IBox): JSX.Element => {
// expensive 비용인 경우, 해당 의존성에 영향을 미치는 n의 변화가 없다면
//재렌더링이 발생해도 다시 계산하지 않음
const result = useMemo(() => sum(n), [n]); // 뒤 배열은 의존성
return (
<div>
<div>
{label}: {result}
</div>
</div>
);
};
useMemo를 사용하여 다음의 경우의 재렌더링에의한 계산을 막을 수 있다:
그러나 다음의 경우는 useMemo만 사용하여 렌더링 최적화가 불가능하다:
이를 해결하기 위하여 React.memo
로 렌더링을 방지할 컴포넌트를 감싸야 한다.
결론부터 말하자면 아니다. React.memo는 다음의 경우에 유리하다.
React.memo는 다음의 경우에 불리하다. 성능적인 이점을 얻지 못한다면 오히려 React.memo를 사용하지 않는 것이 낫다. React.memo는 컴포넌트가 업데이트 되기 전에 컴포넌트가 변화가 일어났는지, 일어나지 않았는지 확인하므로
모든 최적화 과정은 Trade-off 과정이므로, 항상 어떤 것의 기회 비용이 더 큰지를 따져 최적화를 진행하는 것이 좋다.
콜백함수를 prop으로 사용하는 경우, 함수의 참조값이 바뀌어 React.Memo로 감싼 컴포넌트가 이전 props와 현재 props의 동등 비교하는 과정을 통해 false를 반환하게 되므로, useCallback으로 callback 함수 최적화가 필요하다.
useCallback
인가보다.// ... App.tsx
function App(): JSX.Element {
const [foodOn, setFoodOn] = useState(false);
const [servicesOn, setServicesOn] = useState(false);
const [transportationOn, setTransportationOn] = useState(false);
const foodChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => setFoodOn(e.target.checked),
[],
);
const servicesChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => setServicesOn(e.target.checked),
[],
);
const transportationChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) =>
setTransportationOn(e.target.checked),
[],
);
return (
<div className="App">
<Checkbox label="food" on={foodOn} onChange={foodChange} />
<Checkbox label="services" on={servicesOn} onChange={servicesChange} />
<Checkbox
label="transportation"
on={transportationOn}
onChange={transportationChange}
/>
</div>
);
}
// 최적화를 진행한 컴포넌트에서 부모 컴포넌트의 재렌더링에 의한
// 하위 컴포넌트 제랜더링 방지를 위하여 useCallback 사용
const Checkbox = ({ label, on, onChange }: ICheckbox): JSX.Element => {
console.log(label, on);
return (
<label>
{label}
<input type="checkbox" defaultChecked={on} onChange={onChange} />
</label>
);
};
export default React.memo(Checkbox);
파일을 만들고, 파일 경로를 수정하는데 자꾸 대소문자만 다른 모듈이 있다고 떴다. 어떻게 해결해도 잘 해결이 안됬다.
검색을 해보니, 리액트에서는 components 폴더 내부에 각 컴포넌트마다 폴더를 만들고, 컴포넌트는 해당 폴더의 index.tsx에 작성하는 방법을 주로 사용한다고 한다.
그 외에 아직 다른 방법으로 해결할 수 있는지는 찾아보지 못했다.
React.memo() 현명하게 사용하기
경고! 대소문자만 다른 이름을 가진 여러 모듈이 있습니다 | React, typescript, webpack ERROR
React 공식 문서