Written by Paul
Reference: https://relay.dev/docs/tutorial/fragments-1/
ย
Fragment๋ Relay์์ ์ฃผ๋ ํผ์ณ๋ค ์ค ํ๋์ด๋ค.
์ฑ๊ธ ์ฟผ๋ฆฌ์ ํจ์จ์ฑ์ ์ ์งํ๋ฉด์ ๊ฐ๊ฐ์ ์ปดํฌ๋ํธ๋ค์ด ๊ทธ๋ค์ ์์ ๋ง์ ๋ฐ์ดํฐ ์๊ตฌ์ฌํญ์ ๊ฐ์ ์ ์ธํ ์ ์๊ฒ ํ๋ค.
์ด ์น์
์์, ์ฐ๋ฆฌ๋ ํ๋์ ์ฟผ๋ฆฌ๋ฅผ ์ด๋ป๊ฒ ์ฌ๋ฌ fragment๋ค๋ก ๋ถํดํ ์ ์๋์ง ๋ณด์ฌ์ค ๊ฒ ์
๋๋ค.
์์ํ๊ธฐ์ ์์, Story ์ปดํฌ๋ํธ๊ฐ story๊ฐ ํฌ์คํ
๋ ๋ ์ง๋ฅผ ๋ณด์ฌ์ฃผ๊ณ ์ถ๋ค๊ณ ๊ฐ์ ํด๋ด
์๋ค.
๊ทธ๋ ๊ฒ ํ๋ ค๋ฉด, ์๋ฒ๋ก ๋ถํฐ ๋ ๋ง์ ๋ฐ์ดํฐ๊ฐ ํ์ํฉ๋๋ค. ๊ทธ๋์ ์ฐ๋ฆฌ๋ ์ฟผ๋ฆฌ์ ํ๋๋ฅผ ์ถ๊ฐ ํ ๊ฒ ์
๋๋ค.
ย
Newsfeed.tsx
๋ก ๊ฐ์ NewsfeedQuery
๋ฅผ ์ฐพ์, ์๋ก์ด ํ๋๋ฅผ ์ถ๊ฐํด๋ด
์๋ค:const NewsfeedQuery = graphql` query NewsfeedQuery { topStory { title summary createdAt // Add this line poster { name profilePicture { url } } image { url } } } `;
ย
์ด์
Story.tsx
๋ก ๊ฐ์ ๋ ์ง๋ฅผ ๋ณด์ฌ์ฃผ๋๋ก ๋ณ๊ฒฝํด ๋ด
์๋ค.import Timestamp from './Timestamp'; type Props = { story: { createdAt: string; // Add this line ... }; }; export default function Story({story}: Props) { return ( <Card> <PosterByline person={story.poster} /> <Heading>{story.title}</Heading> <Timestamp time={story.createdAt} /> // Add this line <Image image={story.image} /> <StorySummary summary={story.summary} /> </Card> ); }
์ด์ ๋ ์ง๊ฐ ๋ณด์ฌ์ ธ์ผ ํฉ๋๋ค. GraphQL ๋๋ถ์, ์ฐ๋ฆฌ๋ ์๋ก์ด ์๋ฒ์ฝ๋๋ฅผ ๋ฐฐํฌํ์ง ์์๋ ๋์์ต๋๋ค.
ย
ํ์ง๋ง ๋ง์ฝ ์ด๊ฑธ ์๊ฐํด๋ณธ๋ค๋ฉด,
Newsfeed.tsx
๋ฅผ ๋ณ๊ฒฝํด์ผ ํ๋ค๋ฉด? ๋ฆฌ์กํธ ์ปดํฌ๋ํธ ์์ฒด๊ฐ ํฌํจ๋์ด ์์ง ์๋ค๋ฉด? ์ Newsfeed๊ฐ Story ์ปดํฌ๋ํธ๊ฐ ํ์๋ก ํ๋ ํน์ ๋ฐ์ดํฐ๋ฅผ ์๊ฐํด์ผ ํ ๊น? ๋ง์ฝ ๋ฐ์ดํฐ๊ฐ Story์ ์์ ์ปดํฌ๋ํธ์ ์ํด ์๊ตฌ๋๋ค๋ฉด? ๋ง์ฝ ์ปดํฌ๋ํธ๊ฐ ๋ค๋ฅธ ์ฌ๋ฌ๊ณณ์์ ์ฐ์ด๋ ๊ฒ์ด๋ผ๋ฉด?๊ทธ๋ ๋ค๋ฉด ์ฐ๋ฆฌ๋ ๋ฐ์ดํฐ ์๊ตฌ์ฌํญ์ด ๋ณ๊ฒฝ๋๋ค๋ฉด ๋ง์ ์ฌ๋ฌ ์ปดํฌ๋ํธ๋ฅผ ๋ณ๊ฒฝํด์ค์ผ ํ ๊ฒ์
๋๋ค.
์ด๊ฑธ ํผํ๊ธฐ ์ํด์ ๊ทธ๋ฆฌ๊ณ ๋ค๋ฅธ ๋ง์ ๋ฌธ์ ๋ค์ ํผํ๊ธฐ ์ํด์, ์ฐ๋ฆฌ๋ Story๋ฅผ ์ํ ๋ฐ์ดํฐ ์๊ตฌ์ฌํญ๋ค์
Story.tsx
๋ก ์ฎ๊ธธ ์ ์์ต๋๋ค.Story
์ ๋ฐ์ดํฐ ์๊ตฌ์ฌํญ์ Story.tsx
๋ก fragment๋ก ๋ถ๋ฆฌํฉ๋๋ค. Fragment๋ GraphQL์ ๊ฐ๊ฐ ๋๋ ์ง ์กฐ๊ฐ๋ค์
๋๋ค. Relay ์ปดํ์ผ๋ฌ๊ฐ ์์ฑ๋ ์ฟผ๋ฆฌ๋ค๋ก ๋ชจ์ ์ฌ์ฉํฉ๋๋ค. Fragment๋ ๊ฐ๊ฐ ์ปดํฌ๋ํธ๊ฐ ๊ทธ๋ค ์์ ๋ง์ ๋ฐ์ดํฐ ์๊ตฌ์ฌํญ์ ์ ์ํ ์ ์๋๋ก ํฉ๋๋ค.Story
์ ๋ฐ์ดํฐ ์๊ตฌ์ฌํญ๋ค์ ์ด์ fragment๋ก ๋ถํด ํด ๋ด
์๋ค.Step 1 โ Define a fragment
Story.tsx
์ StoryFragment๋ฅผ ์ถ๊ฐํฉ์๋ค.import { graphql } from 'relay-runtime'; const StoryFragment = graphql` fragment StoryFragment on Story { title summary createdAt poster { name profilePicture { url } } thumbnail { url } } `;
topStory
์์ ์ฐ๋ฆฌ๋ ๋ชจ๋ ์
๋ ์
๋ค์ ๊ฐ์ ธ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ทธ๋ค์ ์ฐ๋ฆฌ๋ ์๋ก์ด Fragment ์ ์ธ์ผ๋ก ๋ณต์ฌํ์ต๋๋ค. ์ฟผ๋ฆฌ์ ๋น์ทํ๊ฒ, fragment๋ค์ ์ด๋ฆ์ด ์์ต๋๋ค (StoryFragment
), ์ฐ๋ฆฌ๋ ์ด๊ฑธ ์ ์๋์ ์ฌ์ฉํ ๊ฒ์ด๊ณ , ํ์ง๋ง ๊ทธ๋ค์ GraphQL ํ์
์ธ (Story)๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค. โonโ. ์ด ๋ป์ ์ด fragment๊ฐ Story ๋
ธ๋๋ฅผ ๊ฐ์ง๊ณ ์๋ ๊ณณ์์ ๋ชจ๋ ์ฐ์ผ ์ ์๋ค๋ ์๋ฏธ์
๋๋ค.ย
Step 2 โ Spread the fragment
Go toย
Newsfeed.tsx
ย and modifyย NewsfeedQuery
ย to look like this:const NewsfeedQuery = graphql` query NewsfeedQuery { topStory { ...StoryFragment } } `;
ย
Step 3 โ Call useFragment
import { useFragment } from 'react-relay'; export default function Story({story}: Props) { const data = useFragment( StoryFragment, story, ); return ( <Card> <Heading>{data.title}</Heading> <PosterByline person={data.poster} /> <Timestamp time={data.createdAt} /> <Image image={data.image} /> <StorySummary summary={data.summary} /> </Card> ); }
useFragment
๋ ๋๊ฐ์ง ์ธ์๋ฅผ ๊ฐ์ง๋๋ค:- Graphql tagged string: ์ฐ๋ฆฌ๊ฐ ์ฝ๊ณ ์ถ์ fragment์ literal
- story object: fragment Key
ย
Step 4 โ Typescript types for fragment refs
import type {StoryFragment$key} from './__generated__/StoryFragment.graphql'; type Props = { story: StoryFragment$key; };
Reusing a Fragment in Multiple Places
fragment๋ ๋งํฉ๋๋ค, ๊ฐ ๋
ธ๋์์ ์ด๋ค ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ธฐ ์ํ๋์ง์ ๋ํ ํน์ ํ์
์ ๊ทธ๋ํ ๋
ธ๋๋ค์ด ์ฃผ์ด์ง๋๋ค. fragment ํค๋ ๊ทธ๋ํ์ ์ด๋ค ๋
ธ๋๊ฐ ๋ฐ์ดํฐ๊ฐ ์
๋ ํธ ๋์๋์ง์ ๋ํด ํน์ ํฉ๋๋ค.
Step 1 โ Define the fragment
Image.tsx
import { graphql } from 'relay-runtime'; const ImageFragment = graphql` fragment ImageFragment on Image { url } `;
ย
Step 2 โ Spread the fragment
Story.tsx
const StoryFragment = graphql` fragment StoryFragment on Story { title summary postedAt poster { ...PosterBylineFragment } thumbnail { ...ImageFragment } } `;
PosterByline.tsx
const PosterBylineFragment = graphql` fragment PosterBylineFragment on Actor { name profilePicture { ...ImageFragment } } `;
ย
Step 3 โ Call useFragment
Image.tsx
import { useFragment } from 'react-relay'; import type { ImageFragment$key } from "./__generated__/ImageFragment.graphql"; type Props = { image: ImageFragment$key; ... }; function Image({image}: Props) { const data = useFragment(ImageFragment, image); return <img key={data.url} src={data.url} ... /> }
ย
Step 4 โ Modify once, enjoy everywhere
const ImageFragment = graphql` fragment ImageFragment on Image { url altText } `;
ย
function Image({image}) { // ... <img alt={data.altText} //... }
ย
ย
ย
ย
ย
ย
ย