1. useRef
특징 및 사용 목적
- 값 저장: 컴포넌트가 다시 렌더링되어도 참조 값을 유지할 수 있습니다.
- DOM 접근: 특정 DOM 요소에 직접 접근하거나 조작할 때 사용됩니다.
- 렌더링 영향 없음: 값이 변경되어도 컴포넌트를 다시 렌더링하지 않습니다.
주요 사용 예시
- DOM 요소의 포커스 제어, 크기/위치 확인
- 이전 상태 값 저장
- 타이머가 업데이트 될 때마다 불필요한 렌더링 방지
function Timer() {
const timerRef = useRef(null);
const [time, setTime] = useState(0);
const startTimer = () => {
if (!timerRef.current) {
timerRef.current = setInterval(() => {
setTime((prevTime) => prevTime + 1);
}, 1000);
}
};
const stopTimer = () => {
clearInterval(timerRef.current);
timerRef.current = null;
};
return (
<div>
<p>Time: {time}s</p>
<button onClick={startTimer}>Start</button>
<button onClick={stopTimer}>Stop</button>
</div>
);
}
2. useMemo
특징 및 사용 목적
- 계산된 값의 캐싱: 복잡한 계산 결과를 캐싱하여 성능을 최적화합니다.
- 종속성 배열: 지정된 종속성 값이 변경될 때만 다시 계산합니다.
- 렌더링 성능 개선: 렌더링 과정에서 불필요한 계산을 방지합니다.
주요 사용 예시
- 무거운 연산이나 데이터 변환 최적화
- 컴포넌트에서 조건에 따라 변경되는 데이터 처리
- 자식 컴포넌트에 전달할 복잡한 데이터 생성
function Parent() {
const [count, setCount] = useState(0);
const data = useMemo(() => {
console.log('Generating data...');
return { value: count };
}, [count]); // `count`가 변경될 때만 데이터 재생성
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment</button>
<Child data={data} />
</div>
);
}
function Child({ data }) {
console.log('Child rendered');
return <p>Child received: {data.value}</p>;
}
3. useCallback
특징 및 사용 목적
- 함수 캐싱: 동일한 함수 객체를 재사용하여 불필요한 렌더링을 방지합니다.
- 종속성 배열: 지정된 종속성이 변경될 때만 새로운 함수 객체를 생성합니다.
- 자식 컴포넌트 최적화:
React.memo
와 함께 사용하여 불필요한 렌더링을 줄입니다.
주요 사용 예시
- 부모 컴포넌트에서 자식 컴포넌트로 콜백을 전달할 때, 불필요한 재생성으로 인해 자식 컴포넌트가 다시 렌더링되지 않도록 하고 싶을 때.
function Parent() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
setCount((prevCount) => prevCount + 1);
}, []); // 동일한 함수 객체 유지
return (
<div>
<p>Parent Count: {count}</p>
<Child onClick={handleClick} />
</div>
);
}
const Child = React.memo(({ onClick }) => {
console.log('Child rendered');
return <button onClick={onClick}>Increment Parent Count</button>;
});
비교
Hook | 사용 목적 | 렌더링 영향 |
---|---|---|
useRef |
값 저장, DOM 접근 | X |
useMemo |
계산된 값 캐싱 | O |
useCallback |
함수 캐싱, 자식 컴포넌트 최적화 | O |
useMemo, useCallback 의 차이는 미미하다.
https://www.linkedin.com/feed/update/urn:li:activity:7233818253674889217/
최효빈님의 LinkedIn 활동 보기
로그인 또는 회원 가입 후 더 확인해 보세요.
www.linkedin.com
useMemo(() => {{원하는함수}}, dependencies)
//useCallback 과 비슷해보이는 모습
훅으로 훅 만들기
리액트의 구현 방식 때문에 useReducer
로 useState
를 useRef
로 useMemo
를 구현할 수 있다.
왜일까?
리액트 공식문서를 찾아보면, useRef
, useMemo
, useState
는 결국 fiber에 붙은 hook.memoizedState
를 반환하는 것. 또한, setState
, dispatch
역시 react-reconciler의 dispatch
함수를 어떤 형태로 반환하느냐의 차이다.
useReducer ⇒ useState
function useState<S>(initState: S | (() => S)) : [S, (action: SetStateAction>S>) => void] {
const [state, dispatch] = useReducer(
(state: S, action: SetStateAction<S>): S =>
typeof action === 'function' ? (action as (prevState: S) => S)(state) : action,
typeof initState === 'function' ? (initState as () => S)() : initState
);
return [state, dispatch];
}
useRef ⇒ useMemo
function useMemo<T>(factory: () => T, deps: React.DependencyList): T {
const ref = useRef<{ value : T; deps: React.DependencyList | undefined }>){
value: undefined as T,
deps : undefined,
});
if(!ref.current_deps || !shallowEqual(deps, ref.current.deps)) {
ref.current.value = factory();
ref.current.deps = deps;
}
return ref.current.value;
}
useMemo ⇒ useCallback
function useCallback<T extends (...args: any[]) => any>(
callback: T,
deps: React.DependencyList
): T {
return useMemo(() => callback, deps);
}