Zustand, Recoil, Redux ๋ฑ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ค ๋ณด๋ฉด "selector" ๋ผ๋ ๊ฐ๋
์ ์์ฃผ ์ ํ๊ฒ ๋ฉ๋๋ค.
์ฒ์์๋ โ๊ตณ์ด ์ด๊ฑธ ์ ์จ์ผ ํ์ง?โ ์ถ์ ์๊ฐ์ด ๋ค ์ ์์ง๋ง, ์ค์ ํ๋ก์ ํธ๊ฐ ์ปค์ง์๋ก selector์ ํ์์ฑ๊ณผ ํจ์จ์ฑ์ ์ฒด๊ฐํ๊ฒ ๋ฉ๋๋ค.
์ด ๊ธ์์๋ ํ๋ก ํธ์๋ ๊ฐ๋ฐ์์ ์ ์ฅ์์ Selector๊ฐ ๋ฌด์์ธ์ง, ์ ์ฌ์ฉํ๋์ง, ๊ทธ๋ฆฌ๊ณ Zustand์์ ์ค์ ๋ก ์ด๋ป๊ฒ ํ์ฉํ ์ ์๋์ง๊น์ง ์์ธํ ์ ๋ฆฌํด๋ณด์์ต๋๋ค.
Selector๋ ์ํ์์ ์ํ๋ ๊ฐ์ ์ ํํ๊ฑฐ๋, ๊ฐ๊ณตํด์ ๋ฐํํ๋ ํจ์์ ๋๋ค.
๋จ์ํ ์ํ๋ฅผ ๊ทธ๋๋ก ๊ฐ์ ธ์ค๋ ๊ฒ์ด ์๋๋ผ,
๐ก React์ useMemo์ ๊ฐ๋ ์ ์ผ๋ก ์ ์ฌํ์ง๋ง, store ๋ด๋ถ์์ ์ ์๋๋ฉฐ ์ ์ญ์ ์ผ๋ก ์ฌ์ฌ์ฉํ ์ ์๋ค๋ ์ ์์ ์ฐจ๋ณํ๋ฉ๋๋ค.
โก๏ธ ์๋์. ์ ๋ ํฐ(selector) ๋ Recoil์ ์ ์ฉ ๊ธฐ๋ฅ์ด ์๋๋ผ
โ์ํ ํ์๊ฐ(derived state)โ์ ๊ณ์ฐํ๋ ์ผ๋ฐ์ ์ธ ๊ฐ๋ ์ด์์.
์ฉ์ด | ์๋ฏธ |
---|---|
Selector (์ผ๋ฐ ์ฉ์ด) | ์ํ์์ ํน์ ๊ฐ์ ์ถ์ถํ๊ฑฐ๋ ๊ฐ๊ณตํด ๋ฆฌํดํ๋ ํจ์ (๋ฆฌ์กํธ ์ํ ๊ด๋ฆฌ ๊ณตํต ๊ฐ๋ ) |
Recoil Selector | selector() ํจ์๋ก ๋ฑ๋กํ๋ ๋ด์ฅ API |
Zustand Selector | ๋ด์ฅ API๋ ์๊ณ , ์ง์ ํจ์๋ก ์ ์ํด์ ์ฌ์ฉ |
Redux Selector | createSelector (reselect ๋ผ์ด๋ธ๋ฌ๋ฆฌ)๋ก ๊ตฌํํ๋ ๋ฉ๋ชจ์ด์ ์ด์
ํจ์ |
์ฆ, Recoil์ด ์ ๋ ํฐ๋ผ๋ ๊ฐ๋ ์ ๊ณต์ API๋ก ์ฑํํ์ ๋ฟ,
์ด ๊ฐ๋ ์ ์ํ ๊ด๋ฆฌ์์ ๋๋ฆฌ ์ฐ์ด๋ ์ผ๋ฐ์ ์ธ ๊ฐ๋ ์ด์์.
Zustand์์๋ ์๋์ฒ๋ผ ํจ์๋ก ์ง์ ์ ๋ ํฐ๋ฅผ ์ ์ํฉ๋๋ค.
getSelectedDepartment: () => {
const { selectedDeptId, departments } = get();
return departments.find(d => d.deptId === selectedDeptId) || null;
๊ทธ๋ฆฌ๊ณ ์๋์ฒ๋ผ ์ปดํฌ๋ํธ์์ ์ฌ์ฉํ ์ ์์ด์:
const selected = useGroupStore.getState().getSelectedDepartment();
์ด๋ฐ ๊ฑธ Recoil์์๋ selector()๋ก ๋ฑ๋กํด์ ์ฌ์ฉํ๋ ๊ฒ๋ฟ์ด์์.
createSelector
๋ผ๋ ํจ์๋ก ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ ๊ณตํ๊ณ ์๋์ ๊ฐ์ด ๋ถ์ ์ ๋ณด๋ฅผ ์ฐพ๋ ๋ก์ง์ด ์ฌ๋ฌ ์ปดํฌ๋ํธ์์ ๋ฐ๋ณต๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค:
const dept = departments.find(d => d.deptId === selectedDeptId)
โ ์ด๋ฌํ ์ฝ๋๋ฅผ store ๋ด๋ถ์ selector ํจ์๋ก ์ถ์ถํด๋๋ฉด ์ฌ์ฌ์ฉ์ฑ์ด ๋์์ง๋๋ค:
getSelectedDepartment: () => {
const { selectedDeptId, departments } = get();
return departments.find(dept => dept.deptId === selectedDeptId) || null;
}
์๋ฅผ ๋ค์ด ์ํ ๊ตฌ์กฐ๊ฐ ๋ฐ๋์ด departments
๊ฐ organization.departments
๋ก ๋ณ๊ฒฝ๋๋ค๋ฉด,
์ปดํฌ๋ํธ๋ง๋ค ์ ๋ถ ์์ ์ ํด์ผ ํ์ง๋ง,
โ selector๋ฅผ ์ฌ์ฉํ๋ฉด selector ํ๋๋ง ๊ณ ์น๋ฉด ๋ชจ๋ ์ปดํฌ๋ํธ๊ฐ ์์ฐ์ค๋ฝ๊ฒ ๋ฐ์๋ฉ๋๋ค.
const leaderName = useGroupStore.getState().getLeaderName(5)
์์ฒ๋ผ ์ปดํฌ๋ํธ๋ "์ด๋ป๊ฒ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ์ง"๊ฐ ์๋๋ผ,
"์ด๋ค ๋ฐ์ดํฐ๋ฅผ ํํํ ์ง"์๋ง ์ง์คํ ์ ์๊ฒ ๋์ด UI/๋ก์ง ๋ถ๋ฆฌ(SoC) ๊ฐ ์ ์ด๋ฃจ์ด์ง๋๋ค.
์กฐ๊ฑด๋ฌธ ์์ด ๋ฌด์ฌ์ฝ ์๋์ ๊ฐ์ ์ฝ๋๋ฅผ ์์ฑํ๋ฉด:
const leader = departmentMembers[deptId].find(m => m.position === 1);
โ ์๋ฌ ๋ฐ์ ๊ฐ๋ฅ์ฑ (Cannot read properties of undefined
)์ด ๋์์ง๋๋ค.
ํ์ง๋ง selector ๋ด๋ถ์์ ์์ธ ์ฒ๋ฆฌ๋ฅผ ํด๋๋ฉด ์ปดํฌ๋ํธ์์๋ ์์ฌํ๊ณ ์ฌ์ฉํ ์ ์์ต๋๋ค.
// store ๋ด๋ถ์ ์ ์
getSelectedDepartment: () => {
const { selectedDeptId, departments } = get();
return departments.find(dept => dept.deptId === selectedDeptId) || null;
},
getLeaderName: (deptId: number) => {
const members = get().departmentMembers[deptId] || [];
const leader = members.find(member => member.position === 1);
return leader?.userNm || '';
}
์ปดํฌ๋ํธ์์๋ ๋ค์๊ณผ ๊ฐ์ด ๊ฐ๋จํ๊ฒ ์ฌ์ฉํฉ๋๋ค:
const selectedDept = useGroupStore.getState().getSelectedDepartment();
const leaderName = useGroupStore.getState().getLeaderName(selectedDept?.deptId || 0);
โก๏ธ ์ด๋ด ๊ฒฝ์ฐ, selector๋ฅผ ๋ฏธ๋ฆฌ ์ ์ํด๋๋ ๊ฒ์ด ์ฝ๋ ํ์ง๊ณผ ๊ฐ๋ฐ ์๋ ๋ชจ๋์ ๋์์ด ๋ฉ๋๋ค.
// store/group/selectors.ts
export const getSelectedDepartment = (state: GroupState) => {
return state.departments.find(d => d.deptId === state.selectedDeptId) || null;
};
์ปดํฌ๋ํธ์์๋ ์๋์ฒ๋ผ ์ฌ์ฉํ ์ ์์ต๋๋ค:
const dept = getSelectedDepartment(useGroupStore.getState());
Selector๋ ์ด๋ฐ์๋ ์์ด๋ ์ฝ๋๋ฅผ ์์ฑํ๋ ๋ฐ ๋ฌธ์ ๊ฐ ์์ด ๋ณด์ผ ์ ์์ต๋๋ค.
ํ์ง๋ง ์ฝ๋๊ฐ ์ ์ ์ปค์ง๊ณ ์ํ๊ฐ ๋ณต์กํด์ง์๋ก selector๋ฅผ ์ฌ์ฉํ์ง ์์ผ๋ฉด
Zustand์ ๊ฐ์ ๊ฒฝ๋ ์ํ ๊ด๋ฆฌ ๋๊ตฌ์์๋,
์ํ๋ฅผ โ์ด๋ป๊ฒ ๊ฐ๊ณตํด์ ์ธ์ง๊น์ง ์ค๊ณํ๋ ๊ฒ์ด ์ง์ง ์ํ ๊ด๋ฆฌ์ ํต์ฌ์ ๋๋ค.