로컬 상태 관리와 전역 상태 관리 방법에 대해 알아보자
로컬 상태관리는 useState나 useReducer와 같은 훅을 사용하고 전역 상태는 Context api, Redux-toolkit, Zustand 등을 사용할 수 있다.
"use client";
import { useState } from "react";
import Count from "./components/Count";
import CountDisplayExternal from "./components/CountDisplayExternal";
const LocalStatePage = () => {
const [count, setCount] = useState(0);
const increment = () => setCount((count) => count + 1);
const decrement = () => setCount((count) => count - 1);
const reset = () => setCount(0);
return (
<>
<Count
count={count}
increment={increment}
decrement={decrement}
reset={reset}
></Count>
<CountDisplayExternal count={count}></CountDisplayExternal>
</>
);
};
export default LocalStatePage;
# ./component/count.tsx
import CountButtons from "./CountButton";
import CountDisplay from "./CountDisplay";
const CountPage = ({
count,
increment,
decrement,
reset,
}: {
count: number;
increment: () => void;
decrement: () => void;
reset: () => void;
}) => {
return (
<>
<CountDisplay count={count}></CountDisplay>
<CountButtons
increment={increment}
decrement={decrement}
reset={reset}
></CountButtons>
</>
);
};
export default CountPage;
# ./component/countdisplay.tsx
const CountDisplay = ({ count }: { count: number }) => {
return (
<>
<p>Count: {count}</p>
</>
);
};
export default CountDisplay;
# ./component/countdisplayexternal.tsx
const CountDisplayExternal = ({ count }: { count: number }) => {
return (
<>
<p>Count display external: {count}</p>
</>
);
};
export default CountDisplayExternal;
# ./component/countbutton.tsx
const CountButtons = ({
increment,
decrement,
reset,
}: {
increment: () => void;
decrement: () => void;
reset: () => void;
}) => {
return (
<>
<button onClick={increment}>증가</button>
<button onClick={decrement}>감소</button>
<button onClick={reset}>리셋</button>
</>
);
};
export default CountButtons;
import { createContext } from "react";
interface CountContextType {
count: number;
increment: () => void;
decrement: () => void;
reset: () => void;
}
export const CountContext = createContext<CountContextType | null>(null);
import { useState } from "react";
import { CountContext } from "../contexts/CountContext";
const CountProvider = ({ children }: { children: React.ReactNode }) => {
const [count, setCount] = useState(0);
const increment = () => setCount((count) => count + 1);
const decrement = () => setCount((count) => count - 1);
const reset = () => setCount(0);
return (
<>
<CountContext value={{ count, increment, decrement, reset }}>
{children}
</CountContext>
</>
);
};
export default CountProvider;
import { useContext } from "react";
import { CountContext } from "../contexts/CountContext";
export const useCountContext = () => {
const context = useContext(CountContext);
if (!context) {
throw new Error(
"useCountContext는 CountContext로 감싼 컴포넌트 안에서만 호출할 수 있습니다."
);
}
return context;
};
"use client";
import Count from "./components/Count";
import CountDisplayExternal from "./components/CountDisplayExternal";
import CountProvider from "./providers/CountProvider";
const ContextPage = () => {
return (
<>
<CountProvider>
<Count />
<CountDisplayExternal />
</CountProvider>
</>
);
};
export default ContextPage;
import CountButtons from "./CountButton";
import CountDisplay from "./CountDisplay";
const CountPage = () => {
return (
<>
<CountDisplay />
<CountButtons />
</>
);
};
export default CountPage;
import { useCountContext } from "../hooks/useCountContext";
const CountButtons = () => {
const { increment, decrement, reset } = useCountContext();
return (
<>
<button onClick={increment}>증가</button>
<button onClick={decrement}>감소</button>
<button onClick={reset}>리셋</button>
</>
);
};
export default CountButtons;
import { useCountContext } from "../hooks/useCountContext";
const CountDisplay = () => {
const { count } = useCountContext();
return (
<>
<p>Count(using contextapi): {count}</p>
</>
);
};
export default CountDisplay;
import { useCountContext } from "../hooks/useCountContext";
const CountDisplayExternal = () => {
const { count } = useCountContext();
return (
<>
<p>Count display external: {count}</p>
</>
);
};
export default CountDisplayExternal;
// store 정의
import { create } from "zustand";
interface CountStoreState {
count: number;
increment: () => void;
decrement: () => void;
reset: () => void;
resetIfEven: () => void;
}
export const useCounterStore = create<CountStoreState>((set, get) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
resetIfEven: () => {
const { count } = get();
if (count % 2 === 0) {
set({ count: 0 });
}
},
}));
// 사용하기
import { useCounterStore } from "../store/countstore";
const CountButtons = () => {
const increment = useCounterStore((state) => state.increment);
const decrement = useCounterStore((state) => state.decrement);
const reset = useCounterStore((state) => state.reset);
return (
<>
<button onClick={increment}>증가</button>
<button onClick={decrement}>감소</button>
<button onClick={reset}>초기화</button>
</>
);
};
export default CountButtons;
import { useCounterStore } from "../store/countstore";
const CountDisplay = () => {
const { count } = useCounterStore();
return (
<>
<p>Count(using zustand): {count}</p>
</>
);
};
export default CountDisplay;
import { create } from 'zustand'
import { persist, subscribeWithSelector } from 'zustand/middleware'
export const useCounterStore = create<>() (
persist( // 로컬 스토리지에 저장할 수 있도록 persist()로 감싸기
(set, get) => ({}),
{name: 'counter-store'} // 로컬 스토리지에서 사용할 키 이름
import { create } from 'zustand'
import { persist, subscribeWithSelector } from 'zustand/middleware'
export const useCounterStore = create<>() (
subscribeWithSelector(
persist( // 로컬 스토리지에 저장할 수 있도록 persist()로 감싸기
(set, get) => ({}),
{name: 'counter-store'} // 로컬 스토리지에서 사용할 키 이름
)
)
);
export const useCounterStore = create<>() (
subscribeWithSelector(
persist( // 로컬 스토리지에 저장할 수 있도록 persist()로 감싸기
immer((set, get) => ({
count: 0,
increment: () => set((state) => {state.count += 1},
decrement: () => set((state) => {state.count -= 1},
reset: () => set((state) => {state.count = 0},
...
})
),
{name: 'counter-store'} // 로컬 스토리지에서 사용할 키 이름
)
)
);