์ด ๊ธ์ Tanstack Query์ SSE๋ฅผ ์ฌ์ฉํ๋ ํ๋ก์ ํธ์์ ์ํ ๋๊ธฐํ ๋ฌธ์ ๋ฅผ ๊ฒฝํํ ๋ถ๋ค์ ์ํ ์ฌ๋ก ๊ณต์ ์ ๋๋ค.
์ปค๋ฆฌ์ด๋น์์ ์๋ฆผ ๋๋ฉ์ธ์ ๊ฐ๋ฐํ๋ฉด์ ์ ๋ง ๋ง์ ํธ๋ฌ๋ธ ์ํ ์ด ์์๋ค.
์ค๋์ ๊ทธ ์ค ํ๋์ธ “์๋ฆผ ์์ด์ฝ ์ฝ์ ์ฒ๋ฆฌ ์ ๋ฐ์ดํธ” ์ ๋ํด์ ์ด์ผ๊ธฐํด๋ณด๊ฒ ๋ค.
๋ฌธ์ ์ํฉ
๋จผ์ ์ปค๋ฆฌ์ด๋น์์๋ SSE๋ฅผ ์ฌ์ฉํ์ฌ ์๋ก์ด ์๋ฆผ์ด ์๊ธฐ๋ฉด ๊ทธ ์ฌ๋ถ๋ฅผ boolean์ผ๋ก ๋ฐ์์จ๋ค. ๊ทธ๋ฌ๋ฉด ์ด๋ฅผ header์ ์๋ฆผ ์์ด์ฝ์ ์ ๋ฐ์ดํธ ํด์ค๋ค.
์ด์๋ ์ฌ๊ธฐ์์ ๋ฐ์ํ๋ค.
์ฌ์ฉ์๋ ์๋ฆผ์ ๋ณด๊ธฐ ์ํด ์๋ฆผ ์์ด์ฝ์ ํด๋ฆญํ๋ค.
ํด๋ฆญ ์ /notification ์ผ๋ก ์ด๋ํ๋ค.
์ด๋ ํ, header์ ์๋ฆผ ์์ด์ฝ์ด ์ผ๋ฐ ์์ด์ฝ์ผ๋ก ๋๋์๊ฐ์ผ ํ๋ค.
ํด๋ผ์ด์ธํธ์ ์๋ฒ์ ๊ด์ ์ฐจ์ด
์ฌ๊ธฐ์ ๋ฐฑ์๋์์ ๋ก์ง์ด ์ ํํ ์ผ์นํ์ง ์๋๋ค๋ ์ ์ด ์ด์์ ์๋ฐ์ ์ด์๋ค.
์ฐ์ ์ปค๋ฆฌ์ด๋น์์๋ “์๋ฆผ ํ์ด์ง์ ์ง์ ํจ” = “์๋ฆผ์ ์ฝ์” ์ผ๋ก ๊ฐ์ฃผํ์๋ค.
๐จ ํด๋ผ์ด์ธํธ ์ ์ฅ
- ์๋ฆผ ํ์ด์ง์ ์ง์ ์ ๋ฐ๋ก header์ ์๋ฆผ ์์ด์ฝ์ด ์ ์์ผ๋ก ๋์์์ผ ํ๋ค.
๐๏ธ ์๋ฒ ์ ์ฅ
- ์ ์๋ฆผ๋ค์ ID๋ฅผ PATCH ์์ฒญ์ ํตํด ๋ฐ๊ณ , ํด๋น ์๋ฆผ๋ค์ ์ฝ์ ์ฌ๋ถ๋ฅผ '์์ฝ์' -> '์ฝ์' ์ผ๋ก ์ ๋ฐ์ดํธํ๋ค.
- ์๋ฆผํ ์ด๋ธ์์ ๊ฐ ์ ์ ๋ค์ ์๋ฆผ๊ณผ ์ฝ์ ์ฌ๋ถ๋ฅผ ํจ๊ป ์ ์ฅํ๊ณ ์๊ธฐ ๋๋ฌธ์ด๋ค
hasNewAlarm์ T/F ๋ณํ ์์ ์ ๋ํด์ ํด๋ผ์ด์ธํธ์ ์๋ฒ ์ฌ์ด์ ์ ์ฅ ์ฐจ์ด๊ฐ ๋ฐ์ํ๋ค.
ํ์ง๋ง ์ด๊ฒ ๋๋ฌธ์ ๋ฐฑ์๋์๊ฒ ๋ฐ์ดํฐํ๋๋ฅผ ์ถ๊ฐํ๋ผ๊ณ ํ ์๋ ์๋ ๋ ธ๋ฆ์ด๊ธฐ์ ๋๋ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ ์๊ฐํด๋๋ค.
ํด๊ฒฐ ๋ฐฉ์ ํ๋ณด
[๋ฐฉ๋ฒ 1] useEffect์์ setQueryData๋ก ์ฆ์ false ์ฒ๋ฆฌ
useEffect(() => {
queryClient.setQueryData(['userinfo'], (oldData: any) => {
if (!oldData) return oldData;
if (oldData.hasNewAlarm === false) return oldData;
return {
...oldData,
hasNewAlarm: false,
};
});
}, []);
์ด๋ฐ ์์ผ๋ก ๊ฐ์ ๋ก ์ฟผ๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ์ค์ ํ๋ค.
โ ๋จ์
- PATCH ์์ฒญ์ด ์๋ฃ๋๊ธฐ ์ userInfo ์ฟผ๋ฆฌ๊ฐ stale๋์ด refetch๋๋ฉด:
- ์๋ฒ์์๋ ์์ง hasNewAlarm: true ์ํ๋ผ ๋ค์ true๋ก ๋์์ด
- ์์ด์ฝ์ด ๊น๋นก์๋ค ๋ค์ ์ผ์ง ์ ์์
- ์ผ๊ด์ฑ์ด ๊นจ์ง ๊ฐ๋ฅ์ฑ
[๋ฐฉ๋ฒ 2] PATCH ์๋ฃ ํ refetchQueries
await PATCH(...);
queryClient.refetchQueries(['userInfo'])
PATCH๊ฐ ์ฑ๊ณตํ๋ฉด ์๋ฒ์์ ๋ณ๊ฒฝ๋ userInfo ๋ฐ์ดํฐ๋ฅผ refetch ํ๋ค.
โ ๋จ์
- POST ์๋ต์ด ๋๋ฆฐ ๊ฒฝ์ฐ, ์ฌ์ฉ์๊ฐ ์๋ฆผ ํ์ด์ง ๋ค์ด๊ฐ๋๋ฐ ํค๋ ์๋ฆผ ์์ด์ฝ์ด ํ์ฐธ ํ์ ์ฌ๋ผ์ง
- ์ฆ์ ํผ๋๋ฐฑ์ด ์์
- ์ฒด๊ฐ์ UX๊ฐ ๋๋ ์ด๋๋ค๊ณ ๋๋ ์ ์์
- ๋คํธ์ํฌ ๋ ์ดํด์ ์์กด
UI ๊น๋นก์์ด ์ผ์ด๋ ์ ์๋ ์ํฉ์ ์ ๋ฆฌํด๋ณด์๋ฉด ์๋์ ๊ฐ๋ค.
- ๋คํธ์ํฌ ์ํ๊ฐ ๋๋ฆฐ ํ๊ฒฝ (์: ๋ชจ๋ฐ์ผ 3G)
- ๋ฐฑ์๋ ์๋ต ์ง์ฐ (์: 1~2์ด ์ด์)
- ์๋ฆผ์ ์ฝ์ ์ฒ๋ฆฌํ๋ POST ์์ฒญ๊ณผ, userInfo ์ฟผ๋ฆฌ๊ฐ ๋ ๋ค ํ์ฑํ ์ํ๋ผ refetch ํ์ด๋ฐ์ด ๊ฒน์นจ
ํ์ง๋ง ์ต๋ํ ๋๊ด์ ์ ๋ฐ์ดํธ ํจํด์ ์ ์ฉํ๋๊ฒ UX ์ธก๋ฉด์์ ์ข์ ๊ฒ์ด๋ผ๊ณ ํ๋จํ๋ค.
๋ฐ๋ผ์ ์๋์ ๋ฐฉ๋ฒ์ ์๊ฐํ๋ค.
[๋ฐฉ๋ฒ 3] ๋ฎคํ ์ด์ ์ฌ์ฉ
// PATCH ์์ฒญ ์ค์๋ refetch ํ์ง ์๊ฒ
const mutation = useMutation(markNotificationsAsRead, {
onMutate: async () => {
// ์๋ฆผ ์ฆ์ ๊บผ์ง๊ธฐ
queryClient.setQueryData(['userInfo'], (old) => ({ ...old, hasNewAlarm: false }));
// ๊ธฐ์กด ์ฟผ๋ฆฌ ์ทจ์ (์ค๊ฐ ๊ฐฑ์ ๋ฐฉ์ง)
await queryClient.cancelQueries(['userInfo']);
},
onSuccess: () => {
queryClient.invalidateQueries(['userInfo']);
},
});
100% ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ์ ์ ์งํ ์ ์๋ ๋ฐฉ๋ฒ์ด ๋ง๋ค.
ํ์ง๋ง ์ค์ฌ์ฉ์์ ์๋ฆผ ์ํ ๊น๋นก์์ด 500ms ์ดํ์ ๊ทธ์ณค๊ณ , ์ฌ์ฉ์ ํผ๋๋ฐฑ์์ ํผ๋์ ๋๋ ์ฌ๋ก๊ฐ ์์๋ค.
๋ฐ๋ผ์ ๋ฎคํ ์ด์ ์ ์ค๋ฒ์คํ์ด๋ผ๋ ๊ฒฐ๋ก ์ ์ง์๋ค.
[๋ฐฉ๋ฒ 4] setQueryData์ refetchQueries ๋ชจ๋ ์ฌ์ฉ + ๋กค๋ฐฑ
๋ง ๊ทธ๋๋ก ์์ ๋ฐฉ๋ฒ์ ๋ชจ๋ ์ ์ฉํ๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ๋ ์ถฉ๋ถํ ๋ณด์ฅ๋ ์ ์๋ค.
์ด์ ์๋ฒฝํ ๋๊ด์ ์ ๋ฐ์ดํธ ํจํด์ ์ ์ฉํ๊ธฐ ์ํด์ ๋กค๋ฐฑ ๋ก์ง๋ง ๊ตฌํํ๋ฉด ๋๋ค.
๋กค๋ฐฑ ๋ก์ง์ ์๋์ฒ๋ผ ์์ฑํ์๋ค.
const previousUserInfo = queryClient.getQueryData(['userInfo']);
try {
await PATCH(...);
queryClient.refetchQueries({ queryKey: ['userinfo'] });
} catch (error) {
// ๋กค๋ฐฑ
queryClient.setQueryData(['userInfo'], previousUserInfo);
}
ํ๊ณ
์ด๋ฒ ๊ฒฝํ์ ํตํด ์ค์๊ฐ ๋ฐ์ดํฐ ๋๊ธฐํ๋ ๋จ์ํ UI์ ํ์๋๋๋ ์ ๋ฌธ์ ๊ฐ ์๋๋ผ, ๋ฐ์ดํฐ ์ผ๊ด์ฑ๊ณผ ์ฌ์ฉ์ ์ฒด๊ฐ ์๋, ๊ทธ๋ฆฌ๊ณ ๊ฐ๋ฐ ๋น์ฉ๊น์ง ํจ๊ป ๊ณ ๋ คํด์ผ ํ๋ ์์ญ์ด๋ผ๋ ๊ฑธ ๋ค์ ๋๊ผ๋ค.
์ฒ์์๋ ๊ทธ๋ฅ ์ด์ฐจํผ ๊ธ๋ฐฉ ๊ฐฑ์ ๋ ๊ฑฐ๋๊น refetch๋ง ํด๋ ๋๊ฒ ์ง ๋ผ๊ณ ์๊ฐํ๋ค. ๊ทธ๋ฐ๋ฐ ๋ง์ ํ ์คํธ๋ฅผ ํด๋ณด๋, ๋คํธ์ํฌ๊ฐ ๋๋ฆฐ ํ๊ฒฝ์ด๋ ์ ์ฌ์ ๊ธฐ๊ธฐ์์๋ ์๋ฆผ ์์ด์ฝ์ด ๊น๋นก๊ฑฐ๋ฆฌ๋ ์๊ฐ์ด ๋ณด์๋ค. ์ด๋ฐ ์์ ๋ถ๋ถ๋ ์ ๊ฒฝ์ฐ์ง ์์ ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ ์ค์ํ ๊ฑด ์ด๋ค ์ ํ์ ํ๋ ํธ๋ ์ด๋์คํ๊ฐ ์๋ค๋ ์ฌ์ค์ด๋ค. ๋๊ด์ ์ ๋ฐ์ดํธ๋ฅผ ์ฐ๋ฉด ์ฌ์ฉ์ ์ ์ฅ์์๋ ๋น ๋ฅด๊ฒ ๋ฐ์ํ๋ ๊ฒ์ฒ๋ผ ๋ณด์ฌ์ ์ข์ง๋ง, ๋ง์ฝ ์๋ฒ ์ฒ๋ฆฌ๊ฐ ์คํจํ์ ๋๋ ๋กค๋ฐฑ๊น์ง ์ฑ ์์ ธ์ผ ํ๋ค. ์๊ฐํ ๊ฒ ๋ง์์ง์ง๋ง ์๋น์ค๋ ๊ฒฌ๊ณ ํด์ง๋ค.
์๋ง์ ๊ธฐ์ ๋ค์ด ์์ง๋ง ์ด๋์ ์ด๋ป๊ฒ ์ ์ฉํ๋๋๋ ๋์ ์ ํํ๊ณ , ๊ตฌํ ๋ฐฉ์๋ ์๋๋ฃฉํ์ง๋ง ๊ทธ์ค ๋ฌด์์ ์ ํํ๋๋๋ ๋์ ํ๋จ์ ์ํ๋ค. ๊ทธ ๊ทผ๊ฑฐ๋ค๋ ์์ด์ผ ํ๋ค.
์ด๋ฒ ์ด์๋ฅผ ํตํด ๋จ์ํ ์๋ฆผ ์ํ๋ฅผ ์ฒ๋ฆฌํ๋ ์์ ์ ๋์ด, ๊ธฐ๋ฅ์ ๋ณต์ก๋๋ฅผ ์ด๋๊น์ง ๊ฐ์ ธ๊ฐ ๊ฒ์ธ์ง, ๊ทธ๋ฆฌ๊ณ ์ฌ์ฉ์ ๊ฒฝํ๊ณผ ๊ฐ๋ฐ ํจ์จ์ ๊ท ํ์ ์ด๋ป๊ฒ ์ก์์ง๋ฅผ ๊ณ ๋ฏผํ ์ ์์๋ค. ์์ผ๋ก๋ ํ์ดํ !!
'๐๏ธFrontend' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Figma] ํผ๊ทธ๋ง (0) | 2025.02.20 |
---|