이펙티브 타입스크립트 (댄 밴더캄 지음) 를 읽고 정리
📍요약
✅매핑된 타입을 사용하여 새로운 프로퍼티가 있을 때 인터페이스에 추가를 강제하게 할 수 있다
(값과 타입을 동기화)
📍컴포넌트 최적화 1 : fail close
예를 들어 산점도 컴포넌트를 그릴 때
- 산점도에 필요한 데이터가 바뀌면 리렌더링해야 하지만,
- 컴포넌트의 props로 전달되는 클릭 이벤트 핸들러는 같아도 상관없다
(하지만, 익명함수이므로 아예 비교를 배제해줘야 리렌더링 방지가 가능)
- 예시 코드
interface ScatterProps {
// The data
xs: number[];
ys: number[];
// Display
xRange: [number, number];
yRange: [number, number];
color: string;
// Events
// 익명 함수이므로 리렌더링마다 메모리 주소가 매번 달라짐
onClick: (x: number, y: number, index: number) => void;
}
// 리렌더링이 필요한지 여부를 반환하는 함수
function shouldUpdate(
oldProps: ScatterProps,
newProps: ScatterProps
) {
let k: keyof ScatterProps;
for (k in oldProps) { // 얕은 비교
if (oldProps[k] !== newProps[k]) {
if (k !== 'onClick') return true;
}
}
return false;
}
- 이 방법은 conservative (보수적 접근법) 또는 fail close (에러에 적극적 대처) 방법이다
- 만약 새로운 프로퍼티가 추가되면 반드시 리렌더링되므로 리렌더링이 빡빡하게 일어나는 단점이 있다
- 새로운 프로퍼티가 추가될 수 있는데.. 이것을 타입 체커가 감지하여 에러를 발생시키게끔 수정하면 좋을 것 같다
📍컴포넌트 최적화 2 : 매핑된 타입 활용
매핑된 타입을 활용하여 새로운 props가 추가되면 타입체커가 감지할 수 있게 해준다
interface ScatterProps {
// The data
xs: number[];
ys: number[];
// Display
xRange: [number, number];
yRange: [number, number];
color: string;
// Events
onClick: (x: number, y: number, index: number) => void;
// 새로운 프로퍼티가 추가되면 타입체커가 확인
// onDoubleCLick: () => void;
}
// REQUIRES_UPDATE 객체는 익명함수에 대해서 비교하지 않게 해줌
const REQUIRES_UPDATE: {[k in keyof ScatterProps]: boolean} = {
xs: true,
ys: true,
xRange: true,
yRange: true,
color: true,
onClick: false,
};
// 배열로 작성할 수도 있음
const PROPS_REQUIRING_UPDATE: (keyof ScatterProps)[] = [
'xs',
'ys',
'xRange',
'yRange',
'color',
'onClick'
];
function shouldUpdate(
oldProps: ScatterProps,
newProps: ScatterProps
) {
let k: keyof ScatterProps;
for (k in oldProps) {
// if (oldProps[k] !== newProps[k] && REQUIRES_UPDATE[k]) {
// return true;
// }
if (oldProps[k] !== newProps[k] && PROPS_REQUIRING_UPDATE.includes(k)) {
return true;
}
}
return false;
}
- 매핑된 타입은 한 객체가 또 다른 객체와 정확히 같은 프로퍼티를 가지게 할 때 사용하면 좋다