ReactJS component style
임광규
많은 데이터 랜더링 하기
데이터가 무수히 많아지면, 애플리케이션이 느려지는 것을 체감할 수 있을 정도로 지연이 발생합니다. 성능을 분석해야 할 때는 느려졌다는 느낌만으로는 충분하지 않습니다. 정확히 몇 초가 걸리는지 확인해야 합니다.
크롬 개발자 도구를 통한 성능 모니터링
크롬 개발자 도구의 Performance 탭을 사용하여 측정하면 정확히 몇 초가 걸리는지 확인 가능합니다.
사용법
- 크롬 개발자 도구를 켭니다.
- Performance 탭의 녹화 버튼을 누릅니다.
- 성능을 분석하려는 동작을 합니다.
- 중지(STOP) 버튼을 누르고 성능 분석 결과를 확인 합니다.
Performance 예제 (Function Call에 550ms가 소요된 이벤트 캡처)
느려지는 원인 분석
일반적으로 ReactJS에서 느려지는 원인은 리랜더링과 연관성이 높습니다. 이때 컴포넌트 리랜더링 성능을 최적화 해주는 작업으로, 리랜더링이 불필요할 때는 리랜더링을 방지해 주어야 합니다.
다음과 같은 상황에서 리랜더링이 발생합니다.
- 자신이 전달받은 props가 변경될 때
- 자신의 state가 바뀔 때
- 부모 컴포넌트가 리랜더링될 때
- forceUpdate 함수가 실행될 때
React.memo를 사용하여 컴포넌트 성능 최적화
컴포넌트의 props가 바뀌지 않으면 리랜더링 하지 않도록 설정하여 함수형 컴포넌트의 리랜더링 성능을 최적화 해줄 수 있습니다. 사용법은 아주 간단하게 컴포넌트를 감싸 주기만 하면 됩니다.
import React from 'react';
export default React.memo(({a, b, c}) => {
/* a,b,c 가 바뀌지 않으면 리랜더링을 하지 않습니다. */
})
React.useCallback를 사용하여 함수 재사용하기
리랜더링 될때마다 함수가 새로 만들어 집니다. 이렇게 함수가 계속 만들어지는 상황을 방지하는 방법은 두가지입니다.
- useState의 함수형 업데이트 기능을 사용
- useReducer를 사용
setState에서 React.useCallback 이용 하기 (예제)
const [val, setVal] = React.useState("초기값");
const changeValue = React.useCallback(() => {
setVal(val => val("변경값"));
},[]);
useCallbakc에서 setVal을 사용할 때 그 안에 val =>
을 넣어주면 두번째 파라미터를 빈 배열로 처리할 수 있습니다.
useReducer에서 React.useCallback 이용 하기 (예제)
useReducer를 사용할 때 원래 두 번째 파라미터에 초기 상태를 넣어줘야 하는데, undefined를 넣고 세 번째 파라미터에 초기 상태를 만들어 주는 함수(
initalValue
)를 넣어습니다. 이렇게 하면 컴포넌트가 맨 처음 랜더링 될때만 initalValue 함수가 호출됩니다.
const initalValue = () => "초기 값";
const [value, dispatch] = React.useReducer(reducer, undefined, initalValue);
const changeValue = React.useCallback((val) => {
dispatch({TYPE: "CHANGE", val});
},[]);
불변성 유지
리액트 컴포넌트에서 상태를 업데이트할 때 불변성을 지키는 것은 매우 중요합니다. 불변성이 지켜지지 않으면 객체 내부의 값이 새로워져도 바뀐 것을 감지하지 못합니다.
전개 연산자(… 문법)을 사용하여 객체나 배열 내부의 값을 복사할 때는 얕은 복사(shallow copy)를 하게 됩니다. 즉 내부 값이 완전히 새로 복사되는 것이 아니라 가장 바깥쪽에 있는 값만 복사 됩니다.
react-virtualized를 사용한 랜더링 최적화
react-virtualized를 사용하면 리스트 컴포넌트에서 스크롤되기 전에 보이지 않는 컴포넌트는 랜더링 되지 않고 크기만 차지하게 할수 있습니다.