props가 변경되지 않았다면, 이 리렌더링은 불필요한 연산 낭비입니다. 이를 방지하기 위한 여러 최적화 기법이 있습니다.React.memo: Props 기반의 리렌더링 방지memo는 고차 컴포넌트(HOC)로, 컴포넌트를 감싸서 props가 변경되었을 때만 리렌더링하도록 만듭니다.
React는 이전 props와 현재 props를 얕게(shallowly) 비교하여 변경 여부를 판단합니다.
사용 사례: props가 자주 변경되지 않는 무거운 UI 컴포넌트(e.g., 차트, 복잡한 목록 아이템)에 적합합니다.
import { memo } from 'react';
const MyComponent = memo(function MyComponent(props) {
// 이 컴포넌트는 props가 변경될 때만 리렌더링됩니다.
console.log('MyComponent RENDERED');
return <div>{props.text}</div>;
});
useCallback: 함수 재생성 방지문제점: JavaScript에서 함수는 객체이므로, 컴포넌트가 리렌더링될 때마다 내부에 선언된 함수는 새로운 메모리 주소를 가진 새로운 함수로 다시 생성됩니다. 이로 인해 memo로 감싼 자식 컴포넌트에 이 함수를 prop으로 전달하면, prop이 변경되었다고 인식하여 memo가 무력화됩니다.
useCallback: 함수를 메모이제이션(memoization)하여, 의존성 배열([])의 값이 변경되지 않는 한 함수를 재생성하지 않고 재사용하게 해주는 Hook입니다.
사용법: const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b]);
const App = () => {
const [count, setCount] = useState(0);
// count가 변경될 때만 함수가 재생성됨
const handleClick = useCallback(() => {
console.log('Button clicked!');
}, []); // 의존성 배열이 비어있으므로, 최초 1회만 생성됨
return <MyButton onClick={handleClick} />; // MyButton은 memo로 감싸져 있음
};
key Prop을 이용한 상태 초기화key를 기준으로 컴포넌트를 재사용하며 props만 업데이트합니다. 이로 인해 컴포넌트 내부의 상태(state)는 그대로 유지되어 의도치 않은 동작을 유발할 수 있습니다.key prop을 고유하고 안정적인 값으로 설정하면, React는 key가 다른 엘리먼트는 완전히 다른 것으로 인식하여 이전 컴포넌트를 파괴하고 새로운 상태를 가진 새 컴포넌트를 생성합니다. 이를 역으로 이용하여, 특정 컴포넌트의 상태를 의도적으로 초기화하고 싶을 때 key 값을 변경하는 트릭을 사용할 수 있습니다.Context API의 복잡성과 보일러플레이트(boilerplate)를 줄여주는, 매우 간결하고 직관적인 전역 상태 관리 라이브러리입니다. Redux나 MobX보다 훨씬 배우기 쉽습니다.Store: 애플리케이션의 상태(state)와 상태를 변경하는 액션(action)을 담고 있는 저장소입니다.
create 함수를 사용하여 스토어를 생성하고, 컴포넌트에서는 이 스토어를 Hook처럼 호출하여 상태와 액션을 가져올 수 있습니다.
Provider가 필요 없음: Zustand는 Context와 달리, 앱을 <Provider>로 감쌀 필요가 없어 설정이 매우 간단합니다.
// store/counterStore.js
import { create } from 'zustand';
// 1. Store 생성
const useCounterStore = create((set) => ({
// State
count: 0,
// Actions
increase: () => set((state) => ({ count: state.count + 1 })),
decrease: () => set((state) => ({ count: state.count - 1 })),
}));
export default useCounterStore;
// components/Counter.js
import useCounterStore from '../store/counterStore';
function Counter() {
// 2. 컴포넌트에서 Hook처럼 호출하여 사용
const { count, increase, decrease } = useCounterStore();
return (
<div>
<span>{count}</span>
<button onClick={increase}>+</button>
<button onClick={decrease}>-</button>
</div>
);
}
persist 미들웨어: 상태 영속성 유지문제점: 브라우저를 새로고침하면 모든 상태가 초기화됩니다.
persist 미들웨어: Zustand가 제공하는 미들웨어로, 스토어의 상태를 localStorage와 같은 웹 스토리지에 자동으로 저장하고, 페이지 로드 시 다시 불러옵니다.
사용법: 스토어 생성 시 persist 함수로 감싸주기만 하면 됩니다.
// store/authStore.js
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
const useAuthStore = create(
// persist로 감싸기만 하면 됨
persist(
(set) => ({
isLoggedIn: false,
login: () => set({ isLoggedIn: true }),
logout: () => set({ isLoggedIn: false }),
}),
{
name: 'auth-storage', // localStorage에 저장될 키 이름
}
)
);
React.memo는 props가 변하지 않은 컴포넌트의 불필요한 리렌더링을 막아주는 가장 기본적인 최적화 도구입니다.useCallback은 함수 prop이 계속 재생성되어 memo를 무력화시키는 것을 방지하기 위해 함수 자체를 메모이제이션합니다.Provider가 필요 없는 매우 간결한 문법으로 전역 상태 관리를 가능하게 합니다.persist 미들웨어를 사용하면, 단 몇 줄의 코드로 로그인 상태와 같은 데이터를 새로고침 후에도 유지할 수 있습니다.