Refreshing and Refetching (part. 2)

ํ”„๋ž˜๊ทธ๋จผํŠธ ๋ฆฌํ”„๋ ˆ์‹ฑ

โ€œrefreshing a fragmentโ€์ด๋ผ๋Š” ๊ฒƒ์€, ๊ธฐ์กด์— ํ”„๋ž˜๊ทธ๋จผํŠธ๋กœ ๋ Œ๋”ํ–ˆ๋˜ ๋ฐ์ดํ„ฐ์™€ ๋˜‘๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ํŒจ์นญํ•˜์—ฌ ํ•ด๋‹น ๋ฐ์ดํ„ฐ์˜ ๊ฐ€์žฅ ์ตœ์‹  ๋ฒ„์ „์„ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ›์•„์˜ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

real-time ํŠน์ง• ์ด์šฉํ•˜๊ธฐ

์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๊ฐ€์žฅ ์ตœ์‹  ๋ฒ„์ „์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๊ธฐ ์œ„ํ•ด์„œ ์ฒซ๋ฒˆ์งธ๋กœ ํ•  ์ผ์€, real-time ํ”ผ์ณ๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ด ์ ์ ˆํ•œ์ง€ ํŒ๋‹จํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ธฐ์ ์œผ๋กœ ์ˆ˜๋™์œผ๋กœ ๋ฆฌํ”„๋ ˆ์‹œ ํ•  ํ•„์š” ์—†์ด, ์ž๋™์ ์œผ๋กœ ์ตœ์‹  ๋ฒ„์ „์ด ์œ ์ง€๋˜๋„๋ก ํ•œ๋‹ค.

real-time ๊ธฐ๋Šฅ์˜ ์˜ˆ์‹œ๋กœ๋Š” GraphQL Subscription์ด ์žˆ๋Š”๋ฐ, ์ด๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์„œ๋ฒ„์™€ ๋„คํŠธ์›Œํฌ ๊ณ„์ธต์— ์ถ”๊ฐ€์ ์ธ configuration์ด ํ•„์š”ํ•˜๋‹ค.

useRefetchableFragment

ํ”„๋ž˜๊ทธ๋จผํŠธ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜๋™์ ์œผ๋กœ ๋ฆฌํ”„๋ ˆ์‹œํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š”, ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ํฌํ•จํ•œ ์ฟผ๋ฆฌ๋ฅผ ๋ฆฌํŒจ์น˜ํ•ด์•ผ ํ•œ๋‹ค. ์ฃผ์˜ํ•  ์ ์€, ํ”„๋ž˜๊ทธ๋จผํŠธ๋Š” ์ฟผ๋ฆฌ ์—†์ด ๊ทธ ์ž์ฒด๋กœ ํŒจ์น˜๋  ์ˆ˜ ์—†๋‹ค. ๋ฐ˜๋“œ์‹œ ์ฟผ๋ฆฌ์˜ ์ผ๋ถ€๋กœ์จ ์กด์žฌํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์†์‰ฝ๊ฒŒ ํ”„๋ž˜๊ทธ๋จผํŠธ ์ž์ฒด๋ฅผ โ€œํŒจ์น˜"ํ•  ์ˆ˜ ์—†๋‹ค.

ํ”„๋ž˜๊ทธ๋จผํŠธ ๋ฆฌํ”„๋ ˆ์‹œ๋ฅผ ์œ„ํ•ด์„œ๋Š”, useRefetchableFragment ํ›…๊ณผ @refetchable ๋””๋ ‰ํ‹ฐ๋ธŒ๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค. ์ด๋Š” ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ๋ฆฌํŒจ์น˜ํ•˜๊ธฐ ์œ„ํ•œ ์ฟผ๋ฆฌ๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜์—ฌ refetch ๋ฅผ ์‚ฌ์šฉํ•ด ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ํŒจ์น˜ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

import type {UserComponent_user$key} from 'UserComponent_user.graphql';
// @refetchable ์— ๋”ฐ๋ผ ๋ฆด๋ ˆ์ด๊ฐ€ ์ž๋™ ์ƒ์„ฑํ•ด์ค€ ํƒ€์ž…
import type {UserComponentRefreshQuery} from 'UserComponentRefreshQuery.graphql';

type Props = {
  user: UserComponent_user$key,
};

function UserComponent(props: Props) {
  const [data, refetch] = useRefetchableFragment<UserComponentRefreshQuery, _>(
    graphql`
      fragment UserComponent_user on User
			# @refetchable ๊ฐ€ ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ํŒจ์น˜ํ•˜๊ธฐ ์œ„ํ•ด ๋ฆด๋ ˆ์ด๊ฐ€ ์ฟผ๋ฆฌ๋ฅผ ์ž๋™ ์ƒ์„ฑํ•ด์ค€๋‹ค.
      @refetchable(queryName: "UserComponentRefreshQuery") {
        id
        name
        friends {
          count
        }
      }
    `,
    props.user,
  );

	return (
	  <>
	    <h1>{data.name}</h1>
	    <div>Friends count: {data.friends?.count}</div>
	    <Button
	      onClick={() => refresh()}>
	      Fetch latest count
	    </Button>
	  </>
  );
}
  • useRefetchableFragment ๋Š” useFragment ์™€ ๋น„์Šทํ•˜๊ฒŒ ์ž‘๋™ํ•˜๋Š”๋ฐ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ ์ด ์ถ”๊ฐ€๋œ๋‹ค.

    • @refetchable ๋””๋ ‰ํ‹ฐ๋ธŒ๋กœ ํ‘œ์‹œ๋œ ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ์˜ˆ์ƒํ•œ๋‹ค. @refetchable ๋””๋ ‰ํ‹ฐ๋ธŒ๋Š” โ€œ๋ฆฌํŒจ์น˜ ๊ฐ€๋Šฅํ•œโ€ ํ”„๋ž˜๊ทธ๋จผํŠธ์—๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ๋ฐ, ์ด๋Š” Viewer / Query / Node ๋ฅผ ์ƒ์†๋ฐ›๋Š” ๋ชจ๋“  ํƒ€์ž… (id ํ•„๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ํƒ€์ž…) ์— ์กด์žฌํ•˜๋Š” ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

  • ์ด๋Š” refetch ํ•จ์ˆ˜๋ฅผ ๋ฆฌํ„ดํ•˜๋Š”๋ฐ,

    • Flow-type ๋˜์–ด ์ƒ์„ฑ๋œ ์ฟผ๋ฆฌ๊ฐ€ ์˜ˆ์ƒํ•˜๋Š” ์ฟผ๋ฆฌ ๋ณ€์ˆ˜๋ฅผ ์˜ˆ์ธกํ•œ๋‹ค.

    • ๋‘ ๊ฐœ์˜ Flow ํƒ€์ž… ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๊ฐ–์Œ: ์ƒ์„ฑ๋œ ์ฟผ๋ฆฌ์˜ ํƒ€์ž… (e.g. UserComponentRefreshQuery) ๊ณผ ์ด๋ฏธ ์ถ”๋ก  ๊ฐ€๋Šฅํ•œ ๋‘๋ฒˆ์งธ ํƒ€์ž…์„ ์ œ๊ณตํ•˜์—ฌ _ ๋ฅผ ์ „๋‹ฌํ•ด๋„ ๋œ๋‹ค.

  • refetch ๋Š” 2๊ฐ€์ง€ ์ฃผ์š” input๊ณผ ํ•จ๊ป˜ ํ˜ธ์ถœํ•œ๋‹ค.

    • ์ฒซ๋ฒˆ์งธ ์ธ์ž๋Š” ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ํŒจ์น˜ํ•˜๊ธฐ ์œ„ํ•œ ๋ณ€์ˆ˜ ์„ธํŠธ์ด๋‹ค. ์œ„์˜ ๊ฒฝ์šฐ, refetch ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ๋นˆ ๋ณ€์ˆ˜ ์„ธํŠธ๋ฅผ ์ „๋‹ฌํ•˜๋ฉด ์ฒ˜์Œ ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ํŒจ์น˜ํ•  ๋•Œ ์‚ฌ์šฉํ•œ ๋˜‘๊ฐ™์€ ๋ณ€์ˆ˜๋ฅผ ๋‹ค์‹œ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ํŒจ์น˜ํ•˜๊ฒŒ ๋˜๋ฏ€๋กœ, ๋ฆฌํ”„๋ ˆ์‹œ๋กœ์จ ์ž‘๋™ํ•œ๋‹ค.

    • ๋‘๋ฒˆ์งธ ์ธ์ž๋Š” 'network-only' fetchPolicy ๋ฅผ ์ „๋‹ฌํ•˜์—ฌ ๋„คํŠธ์›Œํฌ๋กœ๋ถ€ํ„ฐ ํŒจ์น˜ํ•˜๊ณ  ๋กœ์ปฌ ๋ฐ์ดํ„ฐ ์บ์‹œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ์„ ๋ณด์žฅํ•œ๋‹ค.

  • refetch ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฆฌ๋ Œ๋”๋งํ•˜๊ณ , ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” fetchPolicy ์— ๋”ฐ๋ผ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ๋ฐœ์ƒํ•˜๋ฏ€๋กœ useRefetchableFragment ๊ฐ€ suspend ๋œ๋‹ค. ์ด๋Š” ์ฆ‰, suspend ๋  ๋•Œ fallback ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•ด ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ Suspense ๋ฐ”์šด๋”๋ฆฌ๋กœ ๊ฐ์‹ธ์•ผ ํ•จ์„ ๋‚ดํฌํ•œ๋‹ค.

Suspense ์‚ฌ์šฉ์„ ํ”ผํ•ด์•ผ ํ•  ๋•Œ

๋ช‡๋ช‡์˜ ๊ฒฝ์šฐ, ์ด๋ฏธ ๋ Œ๋”๋œ ์ฝ˜ํ…์ธ ๋ฅผ ์ˆจ๊ธฐ๋Š” Suspense fallback์„ ๋ณด์—ฌ์ฃผ์ง€ ์•Š์•„์•ผ ํ•  ๋•Œ๊ฐ€ ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ, fetchQuery ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ์ˆ˜๋™์ ์œผ๋กœ ์ถ”์ ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ์ด์   ๋ฆฌํ”„๋ ˆ์‹ฑ ํ•  ๋•Œ, suspending์„ ํ”ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์šฐ๋ฆฌ๋งŒ์˜ isRefreshing ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ์ถ”์ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฝ˜ํ…์ธ  ์ˆจ๊น€ ์—†์ด ์ปดํฌ๋„ŒํŠธ ๋‚ด busy ์Šคํ”ผ๋„ˆ๋‚˜ ๋กœ๋”ฉ UI๋ฅผ ๋ Œ๋”๋ง ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์—์„œ, ๋จผ์ € fetchQuery ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ฟผ๋ฆฌ๋ฅผ ํŒจ์น˜ํ•˜๊ณ  ๋กœ์ปฌ ๋ฆด๋ ˆ์ด ์Šคํ† ์–ด์— ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•œ๋‹ค. fetchQuery ๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ๋๋‚˜๋ฉด, refetch ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ด์ „์˜ ์˜ˆ์‹œ์™€ ๋น„์Šทํ•˜๊ฒŒ ์—…๋ฐ์ดํŠธ ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ Œ๋”๋งํ•˜๋„๋ก ํ•œ๋‹ค.

  • ์ด ์ ์—์„œ refetch ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด, ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ์œ„ํ•œ ๋ฐ์ดํ„ฐ๋Š” ๋กœ์ปฌ ๋ฆด๋ ˆ์ด ์Šคํ† ์–ด์— ์บ์‹œ๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด store-only fetchPolicy ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ suspending์„ ํ”ผํ•˜๊ณ  ์ด๋ฏธ ์บ์‹œ๋œ ๋ฐ์ดํ„ฐ๋งŒ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค.

๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ๋กœ ํ”„๋ž˜๊ทธ๋จผํŠธ ๋ฆฌํŒจ์นญํ•˜๊ธฐ

โ€œrefetching a fragmentโ€๋Š” ์ด๋ฏธ ํŠน์ • ํ”„๋ž˜๊ทธ๋จผํŠธ๋กœ ๋ Œ๋”๋ง๋œ ๋ฐ์ดํ„ฐ์™€ ๋‹ค๋ฅธ ๋ฒ„์ „์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํŒจ์นญํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํ˜„์žฌ ์„ ํƒ๋œ ์•„์ดํ…œ์„ ๋ณ€๊ฒฝํ•  ๋•Œ, ์ด๋ฏธ ๋ณด์—ฌ์ง€๋Š” ์•„์ดํ…œ ๋ฆฌ์ŠคํŠธ์™€ ๋‹ค๋ฅธ ์•„์ดํ…œ๋“ค์„ ๋ Œ๋”๋ง ํ•  ๋•Œ, ํ˜น์€ ๋” ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ ํ˜„์žฌ ๋ Œ๋”๋ง๋œ ์ฝ˜ํ…์ธ ์—์„œ ์ƒˆ๋กญ๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์ฝ˜ํ…์ธ ๋ฅผ ๋ Œ๋”๋ง ํ•˜๋Š” ์ƒํƒœ๋กœ ๋ณ€ํ™”ํ•  ๋•Œ ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ๋ฆฌํŒจ์นญ ํ•œ๋‹ค.

๊ฐœ๋…์ ์œผ๋กœ, ์ด๋Š” ํ˜„์žฌ ๋ Œ๋”๋ง๋œ ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ๋‹ค์‹œ ํŒจ์นญ๊ณผ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜์ง€๋งŒ, ๋‹ค๋ฅธ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ ์ƒˆ๋กœ์šด ์ฟผ๋ฆฌ ๋˜๋Š” ์ƒˆ๋กœ์šด ์ฟผ๋ฆฌ ๋ฃจํŠธ์—์„œ ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ๋ Œ๋”๋ง ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

useRefetchableFragment

  • refetch ๋Š” 2๊ฐ€์ง€ ์ฃผ์š” input๊ณผ ํ•จ๊ป˜ ํ˜ธ์ถœํ•œ๋‹ค.

    • ์ฒซ๋ฒˆ์งธ ์ธ์ž๋Š” ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ํŒจ์น˜ํ•˜๊ธฐ ์œ„ํ•œ ๋ณ€์ˆ˜ ์„ธํŠธ์ด๋‹ค. ์œ„์˜ ๊ฒฝ์šฐ, refetch ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์ƒˆ๋กœ์šด ๋ณ€์ˆ˜ ์„ธํŠธ๋ฅผ ์ „๋‹ฌํ•˜๋ฉด ์ƒˆ๋กญ๊ฒŒ ์ „๋‹ฌ๋œ ๋ณ€์ˆ˜์™€ ํ•จ๊ป˜ ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ํ•ด์น˜ํ•œ๋‹ค. ์ด ๋•Œ ์ œ๊ณตํ•ด์•ผ ํ•˜๋Š” ๋ณ€์ˆ˜๋Š” @refetchable ์ฟผ๋ฆฌ๊ฐ€ ์˜ˆ์ƒํ•˜๋Š” ๋ณ€์ˆ˜ subset ์ด๋‹ค. ํ”„๋ž˜๊ทธ๋จผํŠธ๊ฐ€ id ํ•„๋“œ๋ฅผ ๊ฐ–๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ ์ฟผ๋ฆฌ๋Š” id ๋ฅผ ์š”๊ตฌํ•˜๊ณ , ๋‹ค๋ฅธ ๋ณ€์ˆ˜ ๋˜ํ•œ ํ”„๋ž˜๊ทธ๋จผํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ํ•„๋“œ๋ฅผ ์š”๊ตฌํ•œ๋‹ค.

      • ์œ„์˜ ๊ฒฝ์šฐ ํ˜„์žฌ ์ฝ”๋ฉ˜ํŠธ id ์™€ translationType ๋ณ€์ˆ˜๋ฅผ ์œ„ํ•œ ์ƒˆ๋กœ์šด ๊ฐ’์„ ์ „๋‹ฌํ•˜์—ฌ ๋ฒˆ์—ญ๋œ ์ฝ”๋ฉ˜ํŠธ ๋‚ด์šฉ์„ ํŒจ์น˜ํ•œ๋‹ค.

    • ์œ„์˜ ๊ฒฝ์šฐ ๋‘๋ฒˆ์งธ ์˜ต์…˜ ์ธ์ž๋ฅผ ์ „๋‹ฌํ•˜์ง€ ์•Š๋Š”๋ฐ, ์ด๋Š” ๋””ํดํŠธ fetchPolicy ์ธ store-or-network ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ์œ„ํ•œ ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๊ฐ€ ์ด๋ฏธ ์บ์‹œ๋œ ๊ฒฝ์šฐ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ์Šคํ‚ตํ•จ์„ ์˜๋ฏธํ•œ๋‹ค.

Suspense ์‚ฌ์šฉ์„ ํ”ผํ•ด์•ผ ํ•  ๋•Œ

Last updated