Fragments
Relay์์ React ๊ตฌ์ฑ ์์์ ๋ํ ๋ฐ์ดํฐ ์ข ์์ฑ์ ์ ์ธํ๊ธฐ ์ํ ์ฃผ์ ๋น๋ฉ ๋ธ๋ก์ GraphQL ํ๋๊ทธ๋จผํธ์ ๋๋ค. Fragment ๋ GraphQL ์คํค๋ง์ ์ ๊ณต๋ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ units ์ ๋๋ค.
์ค์ ๋ก๋ GraphQL์ ํ๋์ ํด๋น๋ฉ๋๋ค.
fragment UserFragment on User {
name
age
profile_picture(scale: 2) {
uri
}
}
JavaScript ์ฝ๋ ๋ด์์ ํ๋๊ทธ๋จผํธ๋ฅผ ์ ์ธํ๋ ค๋ฉด ๋ค์ graphql
ํ๊ทธ ๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค .
const {graphql} = require('react-relay');
const userFragment = graphql`
fragment UserFragment_user on User {
name
age
profile_picture(scale: 2) {
uri
}
}
`;
Rendering ํ๋๊ทธ๋จผํธ
ํ๋๊ทธ๋จผํธ์ ๋ํ ๋ฐ์ดํฐ๋ฅผ ๋ ๋๋งํ๊ธฐ ์ํด useFragment
Hook ์ ์ฌ์ฉํ ์ ์์ต๋๋ค .
import type {UserComponent_user$key} from 'UserComponent_user.graphql';
const React = require('React');
const {graphql, useFragment} = require('react-relay');
type Props = {
user: UserComponent_user$key,
};
function UserComponent(props: Props) {
const data = useFragment(
graphql`
fragment UserComponent_user on User {
name
profile_picture(scale: 2) {
uri
}
}
`,
props.user,
);
return (
<>
<h1>{data.name}</h1>
<div>
<img src={data.profile_picture?.uri} />
</div>
</>
);
}
module.exports = UserComponent;
useFragment
ํ๋๊ทธ๋จผํธ ์ ์์ ํ๋๊ทธ๋จผํธ ์ฐธ์กฐ ๋ฅผ ์ทจํ๊ณ ํด๋น ํ๋๊ทธ๋จผํธ ๋ฐ ์ฐธ์กฐ์ ํด๋นํ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํฉ๋๋ค.Fragment ์ฐธ์กฐ ๋ Relay๊ฐ Fragment ์ ์์ ์ ์ธ๋ ๋ฐ์ดํฐ ๋ฅผ ์ฝ๋ ๋ฐ ์ฌ์ฉํ๋ ๊ฐ์ฒด์ ๋๋ค.
๋ณด์ ๋ค์ํผ
UserComponent_user
ํ๋๊ทธ๋จผํธ ์์ฒด๋ ์ ํ์ ํ๋๋ฅผ ์ ์ธ ํ์ง๋ง ํด๋น ํ๋๋ฅผ ์ฝ์ ํน์ ์ฌ์ฉ์๋ฅผ ์์์ผ ํฉ๋๋ค. ์ด๊ฒ์ ํ๋๊ทธ๋จผํธ ์ฐธ์กฐ์ ํด๋นํฉ๋๋ค. ์ฆ, Fragment ์ฐธ์กฐ๋ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ผ๋ ค๋ ์ ํ์ ํน์ ์ธ์คํด์ค์ ๋ํ ํฌ์ธํฐ ์ ๊ฐ์ต๋๋ค.์ปดํฌ๋ํธ๋ ์๋์ผ๋ก ์กฐ๊ฐ ๋ฐ์ดํฐ์ ๋ํ ์ ๋ฐ์ดํธ๋ฅผ ๊ตฌ๋ ํฉ๋๋ค.
์ด ํน์ ๋ฐ์ดํฐ์ ๋ํ ๋ฐ์ดํฐ
User
๊ฐ ์ฑ์ ์ด๋์์๋ ๋ฐ์ดํฐ ์ ๋ฐ์ดํธ๋๋ฉด(์: ์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ๋๋ ๊ธฐ์กด ๋ฐ์ดํฐ ๋ณ๊ฒฝ์ ํตํด) ๊ตฌ์ฑ ์์๋ ์๋์ผ๋ก ์ต์ ์ ๋ฐ์ดํธ๋ก ๋ค์ ๋ ๋๋ง๋ฉ๋๋ค.
Relay๋ ์ปดํ์ผ๋ฌ๊ฐ ์คํ๋ ๋ ์ ์ธ๋ ๋ชจ๋ ํ๋๊ทธ๋จผํธ์ ๋ํ type์ ์๋์ผ๋ก ์์ฑํ๋ฏ๋ก ์ด๋ฌํ ์ ํ์ ์ฌ์ฉํ์ฌ ์ปดํฌ๋ํธ props ์ ํ์ ์ผ๋ก ์ง์ ํ ์ ์์ต๋๋ค.
์์ฑ๋ Flow ์ ํ์๋ ์ ๋ฏธ์ฌ๊ฐ ์๋ ์ ํ์ธ ์กฐ๊ฐ ์ฐธ์กฐ ์ ํ๊ณผ
$key
์ ๋ฏธ์ฌ<fragment_name>$key
๊ฐ ์๋ ์ ํ์ธ ๋ฐ์ดํฐ ๋ชจ์ ์ ํ์ด ํฌํจ$data
๋ฉ๋๋ค<fragment_name>$data
. ์ด๋ฌํ ์ ํ์ ๋ค์ ์ด๋ฆ์ผ๋ก ์์ฑ๋ ํ์ผ์์ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค<fragment_name>.graphql.js
. .์ฐ๋ฆฌ๋ ์์ ์์์ user Props ๊ฐ ํ์ํ ํ๋๊ทธ๋จผํธ ์ฐธ์กฐ๋ก ์ ๋ ฅ๋๊ณ ์์ผ๋ฉฐ, ์ด๋ UserComponent_user.graphql ์์ ๊ฐ์ ธ์จ
UserComponent_user$key
์ ํด๋น๋ฉ๋๋ค.
ํ๋๊ทธ๋จผํธ ์ด๋ฆ์ ์ ์ญ์ ์ผ๋ก ๊ณ ์ ํด์ผ ํฉ๋๋ค. ์ด๋ฅผ ์ฝ๊ฒ ๋ฌ์ฑํ๊ธฐ ์ํด ๋ชจ๋ ์ด๋ฆ๊ณผ ์๋ณ์๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ค์ ๊ท์น์ ์ฌ์ฉํ์ฌ Fragment์ ์ด๋ฆ์ ์ง์ ํฉ๋๋ค
<module_name>_<property_name>
. ์ด๋ ๊ฒ ํ๋ฉด ์ด๋ค ํ๋๊ทธ๋จผํธ๊ฐ ์ด๋ค ๋ชจ๋์ ์ ์๋์ด ์๋์ง ์ฝ๊ฒ ์๋ณํ ์ ์์ผ๋ฉฐ ๋์ผํ ๋ชจ๋์ ์ฌ๋ฌ ํ๋๊ทธ๋จผํธ๊ฐ ์ ์๋ ๋ ์ด๋ฆ ์ถฉ๋์ ํผํ ์ ์์ต๋๋ค.
๋์ผํ ์ปดํฌ๋ํธ ๋ด์ ์ฌ๋ฌ Fragment์์ ๋ฐ์ดํฐ๋ฅผ ๋ ๋๋งํด์ผ ํ๋ ๊ฒฝ์ฐ useFragment
์ฌ๋ฌ ๋ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค.
import type {UserComponent_user$key} from 'UserComponent_user.graphql';
import type {UserComponent_viewer$key} from 'UserComponent_viewer.graphql';
const React = require('React');
const {graphql, useFragment} = require('react-relay');
type Props = {
user: UserComponent_user$key,
viewer: UserComponent_viewer$key,
};
function UserComponent(props: Props) {
const userData = useFragment(
graphql`
fragment UserComponent_user on User {
name
profile_picture(scale: 2) {
uri
}
}
`,
props.user,
);
const viewerData = useFragment(
graphql`
fragment UserComponent_viewer on Viewer {
actor {
name
}
}
`,
props.viewer,
);
return (
<>
<h1>{userData.name}</h1>
<div>
<img src={userData.profile_picture?.uri} />
Acting as: {viewerData.actor?.name ?? 'Unknown'}
</div>
</>
);
}
module.exports = UserComponent;
Composing ํ๋๊ทธ๋จผํธ
GraphQL์์ ํ๋๊ทธ๋จผํธ๋ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๋จ์์ ๋๋ค. ์ฆ, ๋ค๋ฅธ ํ๋๊ทธ๋จผํธ๋ฅผ ํฌํจํ ์ ์์ผ๋ฏ๋ก ๊ฒฐ๊ณผ์ ์ผ๋ก ํ๋๊ทธ๋จผํธ๊ฐ ๋ค๋ฅธ ํ๋๊ทธ๋จผํธ ๋๋ ์ฟผ๋ฆฌ๋ด์ ํฌํจ๋ ์ ์์ต๋๋ค .
fragment UserFragment on User {
name
age
profile_picture(scale: 2) {
uri
}
...AnotherUserFragment
}
fragment AnotherUserFragment on User {
username
...FooUserFragment
}
๊ฐ React ์ปดํฌ๋ํธ๋ ์์์ ๋ฐ์ดํฐ ์ข ์์ฑ์ ๊ฐ์ ธ์ฌ ์ฑ ์์ด ์์ต๋๋ค. ์ฌ๋ฐ๋ฅด๊ฒ ๋ ๋๋งํ๋ ค๋ฉด ์์์ props์ ๋ํด ์์์ผ ํ๋ ๊ฒ๊ณผ ๋ง์ฐฌ๊ฐ์ง์ ๋๋ค. ์ด ํจํด์ ๊ฐ๋ฐ์๊ฐ ์ปดํฌ๋ํธ(ํ์ํ ๋ฐ์ดํฐ, ๋ ๋๋งํ๋ ๊ตฌ์ฑ ์์)์ ๋ํด ๋ก์ปฌ๋ก ์ถ๋ก ํ ์ ์์ง๋ง Relay๋ ์ ์ฒด UI ํธ๋ฆฌ์ ๋ฐ์ดํฐ ์ข ์์ฑ์ ๋ํ ์ ์ญ ๋ณด๊ธฐ๋ฅผ ๋์ถํ ์ ์์์ ์๋ฏธํฉ๋๋ค.
Co-location ๊ณผ ๊ด๋ จ์์ต๋๋ค.
/**
* UsernameSection.react.js
*
* Child Fragment Component
*/
import type {UsernameSection_user$key} from 'UsernameSection_user.graphql';
const React = require('React');
const {graphql, useFragment} = require('react-relay');
type Props = {
user: UsernameSection_user$key,
};
function UsernameSection(props: Props) {
const data = useFragment(
graphql`
fragment UsernameSection_user on User {
username
}
`,
props.user,
);
return <div>{data.username ?? 'Unknown'}</div>;
}
module.exports = UsernameSection;
/**
* UserComponent.react.js
*
* Parent Fragment Component
*/
import type {UserComponent_user$key} from 'UserComponent_user.graphql';
const React = require('React');
const {graphql, useFragment} = require('react-relay');
const UsernameSection = require('./UsernameSection.react');
type Props = {
user: UserComponent_user$key,
};
function UserComponent(props: Props) {
const user = useFragment(
graphql`
fragment UserComponent_user on User {
name
age
profile_picture(scale: 2) {
uri
}
# Include child fragment:
...UsernameSection_user
}
`,
props.user,
);
return (
<>
<h1>{user.name}</h1>
<div>
<img src={user.profile_picture?.uri} />
{user.age}
{/* Render child component, passing the _fragment reference_: */}
<UsernameSection user={user} />
</div>
</>
);
}
module.exports = UserComponent;
์ฌ๊ธฐ์ ์ฃผ์ํ ์ฌํญ์ด ๋ช ๊ฐ์ง ์์ต๋๋ค.
UsernameSection
๋user prop
์ผ๋ก ํ๋๊ทธ๋จผํธ ์ฐธ์กฐ๊ฐ ํ์ํฉ๋๋ค. ์ด์ ์ ์ธ๊ธํ๋ฏ์ด ํ๋๊ทธ๋จผํธ ์ฐธ์กฐ๋ Relay๊ฐ ํ๋๊ทธ๋จผํธ ์ ์์ ์ ์ธ๋ ๋ฐ์ดํฐ๋ฅผ ์ฝ๋ ๋ฐ ์ฌ์ฉํ๋ ๊ฐ์ฒด์ ๋๋ค. ๋ณด์๋ค์ํผ ์์UsernameSection_user
ํ๋๊ทธ๋จผํธ ์์ฒด๋ ์ ํ์ ํ๋๋ฅผ ์ ์ธ ํ์ง๋ง ํด๋น ํ๋๋ฅผ ์ฝ์ ํน์ User
๋ฅผ ์์์ผ ํฉ๋๋ค. ์ด๊ฒ์ด ํ๋๊ทธ๋จผํธ ์ฐธ์กฐ์ ํด๋นํฉ๋๋ค.์ฆ, ํ๋๊ทธ๋จผํธ ์ฐธ์กฐ๋ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ผ๋ ค๋ ์ ํ์ ํน์ ์ธ์คํด์ค์ ๋ํ ํฌ์ธํฐ ์ ๊ฐ์ต๋๋ค.
์ด ๊ฒฝ์ฐ UsernameSection์ ์ ๋ฌ๋ User, ์ฆ ํ๋๊ทธ๋จผํธ ์ฐธ์กฐ์๋ ์ค์ ๋ก ์์ UsernameSection ๊ตฌ์ฑ ์์์์ ์ ์ธํ ๋ฐ์ดํฐ๊ฐ ํฌํจ๋์ด ์์ง ์์ต๋๋ค.
๋์
UsernameSection
์ ํ๋๊ทธ๋จผํธ ์ฐธ์กฐ๋ฅผ ์ฌ์ฉํ์ฌ useFragment๋ฅผ ์ฌ์ฉํ์ฌ ๋ด๋ถ์ ์ผ๋ก ์ ์ธ๋ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ต๋๋ค.์ด๊ฒ์ ๋ถ๋ชจ๊ฐ ์์์ด ์ ์ธํ ๋ฐ์ดํฐ์ ๋ํ ์ข ์์ฑ์ ์์์ ์ผ๋ก ์์ฑํ๋ ๊ฒ์ ๋ฐฉ์งํ๊ณ ๊ทธ ๋ฐ๋์ ๊ฒฝ์ฐ๋ ๋ง์ฐฌ๊ฐ์ง์ด๋ฏ๋ก ๋ค๋ฅธ ์ปดํฌ๋ํธ์ ์ํฅ์ ๋ฏธ์น ์ผ๋ ค ์์ด ์ปดํฌ๋ํธ์ ๋ํด ๋ก์ปฌ๋ก ์ถ๋ก ํ๊ณ ์์ ํ ์ ์์ต๋๋ค.
๊ทธ๋ ์ง ์๊ณ ๋ถ๋ชจ๊ฐ ์์์ ๋ฐ์ดํฐ์ ์ก์ธ์คํ ์ ์๋ ๊ฒฝ์ฐ ์์์ด ์ ์ธํ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๋ฉด ๋ถ๋ชจ๊ฐ ์์๋ ์ ์์ต๋๋ค. ์ด๋ฅผ
๋ฐ์ดํฐ ๋ง์คํน
์ด๋ผ๊ณ ํฉ๋๋ค.์์์ด ์์ํ๋ ํ๋๊ทธ๋จผํธ ์ฐธ์กฐ๋
์์ ํ๋๊ทธ๋จผํธ๋ฅผ ํฌํจํ๋ ๋ถ๋ชจ ํ๋๊ทธ๋จผํธ๋ฅผ ์ฝ์ ๊ฒฐ๊ณผ
์ ๋๋ค. ์ฐ๋ฆฌ์ ์์ ์์์ ์ด๋...UsernameSection_user๋ฅผ ํฌํจํ๋ ๋จํธ์ ์ฝ์ ๊ฒฐ๊ณผ๊ฐ UsernameSection
์ด ์์ํ๋ ๋จํธ ์ฐธ์กฐ๊ฐ ๋จ์ ์๋ฏธํฉ๋๋ค. ์ฆ, useFragment๋ฅผ ํตํด ํ๋๊ทธ๋จผํธ๋ฅผ ์ฝ์ ๊ฒฐ๊ณผ ์ป์ ๋ฐ์ดํฐ๋ ํด๋น ํ๋๊ทธ๋จผํธ์ ํฌํจ๋ ๋ชจ๋ ์์ ํ๋๊ทธ๋จผํธ์ ๋ํ ํ๋๊ทธ๋จผํธ ์ฐธ์กฐ ์ญํ ๋ ํฉ๋๋ค.
Composing ํ๋๊ทธ๋จผํธ into Queries
Relay์ ํ๋๊ทธ๋จผํธ๋ฅผ ์ฌ์ฉํ๋ฉด ์ปดํฌ๋ํธ์ ๋ํ ๋ฐ์ดํฐ ์ข ์์ฑ์ ์ ์ธํ ์ ์์ง๋ง ์์ฒด์ ์ผ๋ก ๊ฐ์ ธ์ฌ ์๋ ์์ต๋๋ค. ๋์ ์ฟผ๋ฆฌ์ ์ง์ ๋๋ ๊ฐ์ ์ ์ผ๋ก ํฌํจ๋์ด์ผ ํฉ๋๋ค. ์ด๊ฒ์ ๋ชจ๋ ํ๋๊ทธ๋จผํธ๊ฐ ๋ ๋๋ง๋ ๋ ์ฟผ๋ฆฌ์ ์ํด์ผ ํจ์ ์๋ฏธํฉ๋๋ค . ๋จ์ผ ํ๋๊ทธ๋จผํธ๋ ์ฌ์ ํ ์ฌ๋ฌ ์ฟผ๋ฆฌ์ ํฌํจ๋ ์ ์์ง๋ง ํ๋๊ทธ๋จผํธ ๊ตฌ์ฑ ์์์ ํน์ ์ธ์คํด์ค๋ฅผ ๋ ๋๋งํ ๋ ํน์ ์ฟผ๋ฆฌ ์์ฒญ์ ์ผ๋ถ๋ก ํฌํจ๋์ด์ผ ํฉ๋๋ค.
ํ๋๊ทธ๋จผํธ๊ฐ ํฌํจ๋ ์ฟผ๋ฆฌ๋ฅผ ๊ฐ์ ธ์ค๊ณ ๋ ๋๋งํ๋ ค๋ฉด ํ๋๊ทธ๋จผํธ ๊ตฌ์ฑ ์น์ ์ ํ์๋ ๊ฒ์ฒ๋ผ ํ๋๊ทธ๋จผํธ๋ฅผ ๊ตฌ์ฑํ๋ ๊ฒ๊ณผ ๋์ผํ ๋ฐฉ์์ผ๋ก ๊ตฌ์ฑํ๋ฉด ๋ฉ๋๋ค
/**
* UserComponent.react.js
*
* Fragment Component
*/
import type {UserComponent_user$key} from 'UserComponent_user.graphql';
const React = require('React');
const {graphql, useFragment} = require('react-relay');
type Props = {
user: UserComponent_user$key,
};
function UserComponent(props: Props) {
const data = useFragment(
graphql`...`,
props.user,
);
return (...);
}
/**
* App.react.js
*
* Query Component
*/
import type {AppQuery} from 'AppQuery.graphql';
import type {PreloadedQuery} from 'react-relay';
const React = require('React');
const {graphql, usePreloadedQuery} = require('react-relay');
const UserComponent = require('./UserComponent.react');
type Props = {
appQueryRef: PreloadedQuery<AppQuery>,
}
function App({appQueryRef}) {
const data = usePreloadedQuery<AppQuery>(
graphql`
query AppQuery($id: ID!) {
user(id: $id) {
name
# Include child fragment:
...UserComponent_user
}
}
`,
appQueryRef,
);
return (
<>
<h1>{data.user?.name}</h1>
{/* Render child component, passing the fragment reference: */}
<UserComponent user={data.user} />
</>
);
}
์ฐธ๊ณ :
์์ ๋๋ ํ๋๊ทธ๋จผํธ ์ฐธ์กฐ ๋
UserComponent
ํ๋๊ทธ๋จผํธ๋ฅผ ํฌํจํ๋ ์์ ์ฟผ๋ฆฌ๋ฅผ ์ฝ์ ๊ฒฐ๊ณผ์ด๋ฉฐ, ์ด ๊ฒฝ์ฐ์๋...UsernameSection_user
. ์ฆ, ์data
๊ฒฐ๊ณผ๋ก ์ป์ ๊ฒ์usePreloadedQuery
ํด๋น ์ฟผ๋ฆฌ์ ํฌํจ๋ ๋ชจ๋ ํ์ ํ๋๊ทธ๋จผํธ์ ๋ํ ํ๋๊ทธ๋จผํธ ์ฐธ์กฐ ์ญํ ๋ ํฉ๋๋ค.์ด์ ์ ์ธ๊ธํ๋ฏ์ด ๋ชจ๋ ํ๋๊ทธ๋จผํธ๋ ๋ ๋๋ง๋ ๋ ์ฟผ๋ฆฌ์ ์ํด์ผ ํฉ๋๋ค.
์ฆ, ๋ชจ๋ ํ๋๊ทธ๋จผํธ ์ปดํฌ๋ํธ๋ ์ฟผ๋ฆฌ์ ํ์ ํญ๋ชฉ์ด์ด์ผ ํฉ๋๋ค .
Last updated