posts / react-query

posts / react-query

μ’…λ₯˜
νŽ˜μ΄μ§€
μ½”λ“œ
μž‘μ„±μž

raect-query 적용 μ „ posts

posts νŽ˜μ΄μ§€λŠ” λ¬΄ν•œ 슀크둀둜 좔가적인 포슀트λ₯Ό 더 μš”μ²­ν•΄μ˜€λŠ” 역할을 λ‹΄λ‹Ήν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.
  • fetchMorePosts
    • offset 이 λ³€ν•  λ•Œλ§ˆλ‹€ λ¬΄ν•œ μŠ€ν¬λ‘€μ—μ„œ 좔가적인 ν¬μŠ€νŠΈλ“€μ„ λΆˆλŸ¬μ˜΅λ‹ˆλ‹€.
  • fetchNewPosts
    • 채널 μ„ νƒμ‹œ (채널 아이디가 λ³€ν•  λ•Œλ§ˆλ‹€) μƒˆλ‘œμš΄ ν¬μŠ€νŠΈλ“€μ„ λΆˆλŸ¬μ˜΅λ‹ˆλ‹€.
const fetchMorePosts = useCallback(async () => { if (offset > 0 && postsData.length >= 10) { const data = await getPosts(channelId, offset); const editedData = editPostData(data.data); setPostsData([...postsData, ...editedData]); } }, [offset]); const fetchNewChannel = useCallback(async () => { const data = await getPosts(channelId, 0); const reformedData = editPostData(data.data); setPostsData(reformedData); setOffset(0); }, [channelId]);
useEffect(() => { fetchNewChannel(); }, [channelId]); useEffect(() => { fetchMorePosts(); }, [offset]);
이제 이 비동기 μ²˜λ¦¬λ“€μ„ ν˜œμ„±λ‹˜κ»˜μ„œ μ•Œλ €μ£Όμ‹  react-query 둜 바꿔보렀고 ν•©λ‹ˆλ‹€.

react-query μ†Œκ°œ

μš°μ„  react-query λ₯Ό μ‚¬μš©ν•˜κΈ° μœ„ν•΄ ν”„λ‘œμ νŠΈ μ΅œμƒλ‹¨ μ»΄ν¬λ„ŒνŠΈμ— λ‹€μŒκ³Ό 같이 QueryClientProvider λ₯Ό μ„€μ •ν•΄μ€λ‹ˆλ‹€.
// App.tsx import { QueryClient, QueryClientProvier } from 'react-query'; const queryClient = new QueryClient(); return ( <QueryClientProvider client={queryClient} > <App /> </QueryClientProvider> )
posts λ₯Ό λ°›μ•„μ˜€λŠ” 경우 GET μš”μ²­μ„ λ³΄λ‚΄λ―€λ‘œ useQuery λ₯Ό μ‚¬μš©ν•˜κ²Œ λ©λ‹ˆλ‹€.
useQuery λŠ” λ‹€μŒκ³Ό 같이 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

useQuery(key, callback, options)

λ‹€μŒ 두가지 λ°©λ²•μœΌλ‘œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
const { data, isLoading, ... } = useQuery(queryKey, queryFn, { }); const result = useQuery({ queryKey, queryFn, });
λ§€κ°œλ³€μˆ˜
  • key
    • λ°›μ•„μ˜¬ 데이터λ₯Ό μ‹λ³„ν•˜λŠ” λ¬Έμžμ—΄ ν˜Ήμ€ λ°°μ—΄ κ°’μž…λ‹ˆλ‹€.
      λ°°μ—΄μ˜ 경우 첫번째 μΈμžλ‘œλŠ” 데이터λ₯Ό μ‹λ³„ν•˜λŠ” λ¬Έμžμ—΄μ„, λ‚˜λ¨Έμ§€ μΈμžλ‘œλŠ” μ½œλ°±ν•¨μˆ˜ λ‚΄λΆ€λ‘œ 전달할 λ§€κ°œλ³€μˆ˜λ₯Ό λ°›μ•„μ˜¬ 수 μžˆμŠ΅λ‹ˆλ‹€.
  • callback
    • 비동기 처리 ν•¨μˆ˜κ°€ λ“€μ–΄κ°‘λ‹ˆλ‹€. μ—¬κΈ° API ν˜ΈμΆœμ„ λ„£μœΌλ©΄ λ©λ‹ˆλ‹€.
  • options
    • API μš”μ²­μ‹œ λ‹€μ–‘ν•œ μ˜΅μ…˜μ„ μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€. ν•΄λ‹Ή μ˜΅μ…˜μ€ μ—¬κΈ°μ„œ μ‚¬μš©ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ μƒλž΅ν•©λ‹ˆλ‹€!
λ°˜ν™˜κ°’
λ‹€μŒκ³Ό 같은 λ°˜ν™˜κ°’μ„ κ°€μ Έμ˜¬ 수 μžˆμŠ΅λ‹ˆλ‹€.
const { isLoading, isError, data, error } = useQuery( // ... )
  • isLoading
    • μΊμ‹±λœ 데이터가 μ—†λŠ” 경우 λ‘œλ”© 여뢀에 따라 true ν˜Ήμ€ false 의 값을 κ°€μ§‘λ‹ˆλ‹€.
      μΊμ‹±λœ 데이터가 μžˆλŠ” 경우 false 의 값을 κ°€μ§‘λ‹ˆλ‹€.
  • isError
    • μ—λŸ¬κ°€ λ°œμƒν•œ 경우 true κ°€ λ©λ‹ˆλ‹€.
  • data
    • μš”μ²­μ— μ„±κ³΅ν•œ 경우 λ°›μ•„μ˜¬ λ°μ΄ν„°μž…λ‹ˆλ‹€.
  • error
    • 쿼리 ν•¨μˆ˜μ— 였λ₯˜κ°€ λ°œμƒν•œ 경우 였λ₯˜ 객체λ₯Ό λ°›μŠ΅λ‹ˆλ‹€.
  • refetch
    • μ—¬κΈ°μ„œ μΆ”κ°€μ μœΌλ‘œ refetch λ₯Ό λ°›μ•„μ˜¬ 수 μžˆλŠ”λ°, refetch λŠ” μˆ˜λ™μœΌλ‘œ ν•΄λ‹Ή 쿼리λ₯Ό λ‹€μ‹œ μš”μ²­ν•©λ‹ˆλ‹€.

react-query 적용

μœ„ 방법 쀑 λ‘λ²ˆμ§Έ 방법을 μ‚¬μš©ν•˜μ—¬ posts μ½”λ“œμ— μ μš©ν•˜λ©΄ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.
  • key 값은 getChannelPosts 둜 μ„€μ •ν•΄μ£Όμ—ˆλ‹€. 그리고 channelId 와 offset 을 ν•¨μˆ˜ λ§€κ°œλ³€μˆ˜λ‘œ λ„˜κ²¨μ€λ‹ˆλ‹€.
  • μ½œλ°±ν•¨μˆ˜λ‘œ μ‚¬μš©ν•  비동기 ν•¨μˆ˜λ₯Ό λ‹€μŒκ³Ό 같이 μ§€μ •ν•©λ‹ˆλ‹€.
const { data } = useQuery({ queryKey: ['getChannelPosts', channelId, offset], queryFn: async () => { await getPosts(channelId, offset) }, })
channelId 와 offset 을 인자둜 μ „λ‹¬ν•΄μ£Όμ—ˆμœΌλ―€λ‘œ 두 값이 λ°”λ€” λ•Œλ§ˆλ‹€ μžλ™μœΌλ‘œ refetch κ°€ μ‹€ν–‰λ©λ‹ˆλ‹€.
λ”°λΌμ„œ 기쑴의 κΈ΄ μ½”λ“œλ₯Ό λ‹€μŒκ³Ό 같이 μˆ˜μ •ν•΄μ€„ 수 μžˆμŠ΅λ‹ˆλ‹€.

μˆ˜μ • μ „

const fetchMorePosts = useCallback(async () => { if (offset > 0 && postsData.length >= 10) { const data = await getPosts(channelId, offset); const editedData = editPostData(data.data); setPostsData([...postsData, ...editedData]); } }, [offset]); const fetchNewChannel = useCallback(async () => { const data = await getPosts(channelId, 0); const reformedData = editPostData(data.data); setPostsData(reformedData); setOffset(0); }, [channelId]); useEffect(() => { fetchNewChannel(); }, [channelId]); useEffect(() => { fetchMorePosts(); }, [offset]);

μˆ˜μ • ν›„

const { data: postsData } = useQuery({ queryKey: ['getChannelPosts', channelId, offset], queryFn: async () => { const data = await getPosts(channelId, offset); const editedData = editPostData(data); return offset === 0 ? editedData : [...data, ...editedData]; } });

μΆ”κ°€ 문제

포슀트 10개 미만일 μ‹œ μ˜€ν”„μ…‹ 적용 μ•ˆ ν•˜κΈ°

  1. λ§ˆμ§€λ§‰ μžμ‹ μš”μ†Œλ₯Ό κ΄€μ°°ν•˜λ©΄ observer κ°€ offset 을 μ¦κ°€μ‹œν‚΅λ‹ˆλ‹€. μ—¬κΈ°μ„œ 더 뢈러올 ν¬μŠ€νŠΈκ°€ μ—†μŒμ—λ„, 즉 ν¬μŠ€νŠΈκ°€ 10개 미만인 κ²½μš°μ—λ„ λ§ˆμ§€λ§‰ μš”μ†Œκ°€ κ°€μ‹œμ„±μ΄ true κ°€ 되며 offset 이 μ¦κ°€ν•˜κ²Œ λ©λ‹ˆλ‹€.
    1. 그리고 offset 이 λ³€ν•˜κ²Œ 됨으둜써 좔가적인 포슀트λ₯Ό 뢈러였게 λ©λ‹ˆλ‹€. 더 μž‘μ„±λœ ν¬μŠ€νŠΈκ°€ μ—†μœΌλ‹ˆ postsData κ°€ undefined κ°€ λ˜μ–΄ λΉˆν™”λ©΄μ΄ 좜λ ₯λ©λ‹ˆλ‹€.
      κ·Έλž˜μ„œ μ•„λž˜μ™€ 같이 childNode κ°€ 10 이상인 κ²½μš°μ—λ§Œ κ°€μ‹œμ„±μ„ κ΄€μ°°ν•˜λ„λ‘ μˆ˜μ •ν•˜μ˜€μŠ΅λ‹ˆλ‹€.
      useEffect(() => { if ( postsRef.current && postsRef.current.childNodes.length >= 10 ) { const { lastChild } = postsRef.current; lastChild && observe(lastChild); } }, [postsData]);
  1. λ¬΄ν•œ 슀크둀이 μ—λŸ¬κ°€ λ‚˜λŠ” λ¬Έμ œκ°€ μƒκ²¨μ„œ console 을 좜λ ₯ν•΄λ³΄λ‹ˆ react-query 둜 λ°›μ•„μ˜€λŠ” 데이터λ₯Ό postsData 에 넣어놓고, μƒˆλ‘œμš΄ 데이터λ₯Ό μΆ”κ°€μ μœΌλ‘œ λ„£μ–΄μ£Όλ €κ³  ν–ˆλŠ”λ° 이전 데이터가 undefined κ°€ λ˜λ©΄μ„œ spread μ—°μ‚°μžκ°€ μ μš©λ˜μ§€ μ•ŠλŠ” λ¬Έμ œκ°€ 생겼닀.
    1. κ²°κ΅­ postsData λ₯Ό state 둜 λ”°λ‘œ λΆ„λ¦¬ν•˜κ³ , react-query 둜 λ°›μ•„μ˜€λŠ” 데이터가 μ—…λ°μ΄νŠΈ 될 λ•Œλ§ˆλ‹€ postsData λ₯Ό λ³€κ²½ν•˜λŠ” 둜직으둜 λ³€κ²½ν–ˆλ‹€.
      const [postsData, usePostsData] = useState<EditedPost[]>([]); const { data } = useQuery({ queryKey: ['getChannelPosts', channelId, offset], queryFn: async () => { const data = await getPosts(channelId, offset); const editedData = editPostData(data); return editedData; } }); useEffect(() => { if (data) { setPostsData(offset === 0 ? data : [...postsData, ...data]); } }, []);