Zustand에 대하여 공부하기 앞서, 왜 Zustand인지 알아보도록 하겠다. 우선, Zustand vs Recoil vs Jotai vs Redux vs Context API 등 전역상태관리에 대해 여러가지 방법들이 존재한다. 그중에 Zustand를 택한건 크게 두가지가 있다.
우선 너무 쉽다. Recoil도 배웠을 때는 어렵지 않았다. 솔직히 Redux를 써보고 Recoil을 사용해서 인지는 몰라도, 한번 RecoilProvider로 감싸기만 하면, const state를 관리할 수 있다. 하지만 Redux는 여기서 Provider로 감싸지도 않고 사용할 수 있다. 그냥 상태관리를 해주는 파일을 하나 만들어, 여기서만 정해진 함수로 상태를 바꿀 수 있게 관리를 해주면, 전역 상태관리로 사용할 수 있다.
다음은 트렌드이다. 처음에는 아무리 그래도 React에서 100% 호환되게 서포트 해주는 Recoil이 다운로드수나 인기상으로 더 높다고 생각했다. 그렇게 전역 상태관리로 Recoil을 선택하고, 마지막으로 npm trend를 확인했는데, Zustand가 압도적으로 높았다. 여기서, Zustand를 써보기로 결심하고 공부를 시작해보았다.
놀라운 Zustand의 성장세..!
간단하게 전역 상태 관리를 해보자
우선 간단하게 ID를 메인 페이지에서 입력하면, 추후에 모든 페이지에 적용이 되게 관리하고 싶어, 전역 상태를 채용했다고 가정해보겠다. 그럼 구현해야 되는 순서는 다음과 같다.
typescript에 맞춰 interface를 만드는것에 주의
import create from "zustand";
interface ID {
id: string;
setId: (id: string) => void;
}
const IdStore = create<ID>((set) => ({
id: "init",
setId: (id) => {
set((state) => ({ id: id }));
},
/*
setId: (by) => {
set((state) => ({ id: by }));
}, // 이게 더 보기 편할 수 있음
*/
}));
export default IdStore;
입력하지 않으면 페이지가 넘어가지 않음
export default function InputID() {
const navigate = useNavigate();
const { id, setId } = IdStore();
const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
navigate(`/lobby`);
};
const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setId(event.target.value);
};
return (
<Form onSubmit={onSubmit}>
<Input
autoComplete="off"
onChange={onChange}
placeholder="Enter ID"
id="nickname"
/>
<Button disabled={!id.length}>Enter</Button>
</Form>
);
}
export default function Lobby() {
const { id } = IdStore();
return (
<Container>
<Header>Lobby</Header>
<Me>name: {id} </Me>
</Container>
);
}
이렇게 구성해서 확인해보았다.
그리고, 실시간으로 전역상태가 관리되고 있는지 확인하기 위해 한 페이지에서 다른 컴포넌트에서 한 전역상태를 가지고 테스트도 해 보았다.
import create from "zustand";
interface BearState {
bears: number;
increase: (by: number) => void;
}
const useStore = create<BearState>()((set) => ({
bears: 0,
increase: (by) => set((state) => ({ bears: state.bears + by })),
}));
export default useStore;
function TestOne() {
const navigate = useNavigate();
const { bears, increase } = useStore();
const [id, setId] = useState<number>(0);
// const increasePopulation = useStore((state) => state.increase);
const formHandler = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
return increase(1);
};
return (
<Container>
<form onSubmit={formHandler}>
<button type="submit">incrase</button>
</form>
<TestTwo />
</Container>
);
}
export default TestOne;
function TestTwo() {
const { bears } = useStore();
return (
<Container>
<h1>{bears}</h1>
</Container>
);
}
export default TestTwo;
잘 되는 모습을 볼 수 있다