Step 1. Create React App
Copy # NPM
npx create-react-app your-app-name
# Yarn
yarn create react-app your-app-name
Copy # NPM
cd your-app-name
npm start
# Yarn
cd your-app-name
yarn start
Step 2. Fetch GraphQL (Relay ์์ด fetch() ์ฌ์ฉ)
2.1. GitHub GraphQL Authentication
Copy # your-app-name/.env.local
REACT_APP_GITHUB_AUTH_TOKEN=<TOKEN>
2.2. A fetchGraphQL Helper
Copy // your-app-name/src/fetchGraphQL.js
async function fetchGraphQL(text, variables) {
...
// Fetch data from GitHub's GraphQL API:
const response = await fetch('https://api.github.com/graphql', {
method: 'POST',
...,
body: JSON.stringify({
query: text,
variables,
}),
});
// Get the response as JSON
return await response.json();
}
export default fetchGraphQL;
2.3. Fetching GraphQL From React
Copy // your-app-name/src/App.js
...
function App() {
// We'll load the name of a repository, initially setting it to null
const [name, setName] = useState(null);
// When the component mounts we'll fetch a repository name
useEffect(() => {
let isMounted = true;
fetchGraphQL(`
query RepositoryNameQuery {
# feel free to change owner/name here
repository(owner: "facebook" name: "relay") {
name
}
}
`).then(response => {
// Avoid updating state if the component unmounted before the fetch completes
// ๋ฐ์ดํฐ ํจ์นญ์ด ์๋ฃ๋๊ธฐ ์ unMount ๋๋ ๊ฒฝ์ฐ ์ฒ๋ฆฌ
if (!isMounted) {
return;
}
const data = response.data;
setName(data.repository.name);
}).catch(error => {
console.error(error);
});
return () => {
isMounted = false;
};
}, [fetchGraphQL]);
// Render "Loading" until the query completes
return (
<div className="App">
<header className="App-header">
<p>
{name != null ? `Repository: ${name}` : "Loading"}
</p>
</header>
</div>
);
}
export default App;
Step 3. When To Use Relay (Relay ์ฌ์ฉํด ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ)
step2๋ฅผ ์ฌ์ฉํ๋ฉด, ์ดํ๋ฆฌ์ผ์ด์
์ ๊ท๋ชจ๊ฐ ์ปค์ง๋ ์๋์ ํฌ๊ธฐ์ ๋์ํ๊ธฐ ์ด๋ ค์์ง๋ค.
์ด ๋ Relay๋ฅผ ์ฌ์ฉํ๋ฉด ๋น ๋ฅด๊ณ ๋ฏฟ์ ์ ์๋ ๋ฐฉ์์ผ๋ก ์ด์ ๋์ํ ์ ์๋๋ฐ, ์ด์ ๋ ๋ค์๊ณผ ๊ฐ๋ค.
GraphQL ํ๋๊ทธ๋จผํธ, ๋ฐ์ดํฐ ์ผ๊ด์ฑ, mutations์ ์ปดํฌ๋ํธ์ ์์น์์ผ ๋ฐ์ดํฐ ์์กด์ฑ์ ๋ชจ์๋๊ธฐ (colocating)
Step 4. Adding Relay To Our Project
Relay๋ 3๊ฐ์ง ํต์ฌ์ผ๋ก ์ด๋ฃจ์ด์ ธ์๋ค.
relay-compiler
: ์ปดํ์ผ๋ฌ (๋น๋ ํ์์ ์ฌ์ฉ๋จ)
relay-runtime
: ์ฝ์ด ๋ฐํ์ (React ์นํ์ )
react-relay
: React integration layer
Copy # NPM Users
npm install --save relay-runtime react-relay
npm install --save-dev relay-compiler babel-plugin-relay
# Yarn Users
yarn add relay-runtime react-relay
yarn add --dev relay-compiler babel-plugin-relay
4.1. Configure Relay Compiler
Relay example app์ .graphql
์คํค๋ง ์นดํผ๋ฅผ ๋ค์ด๋ก๋ ๋ฐ๊ธฐ ์ํด
Copy cd your-app-name
curl https://raw.githubusercontent.com/relayjs/relay-examples/main/issue-tracker/schema/schema.graphql > schema.graphql
package.json ์ค์ ์ ๋ค์๊ณผ ๊ฐ๋ค.
Copy // your-app-name/package.json
{
...
"scripts": {
...
"start": "yarn run relay && react-scripts start",
"build": "yarn run relay && react-scripts build",
"relay": "yarn run relay-compiler $@"
...
},
"relay": {
"src": "./src/",
"schema": "./schema.graphql"
}
...
}
Copy cd your-app-name
yarn start
์ฌ๊ธฐ์, GraphQL์ ์ฌ์ฉํ๊ฒ ๋๋ฉด Relay๋ ์ด๋ฅผ ๊ฐ์งํ์ฌ ํด๋น ํ๋ก์ ํธ์์ ์์ฑํ ์ฟผ๋ฆฌ๋ฅผ ๋ํ๋ด๋ ์ฝ๋๋ฅผ your-app-name/src/__generated__/
์ ์์ฑํ๋ค.
4.2. Configure Relay Runtime
์ปดํ์ผ๋ฌ ์ค์ ์ด ์๋ฃ๋์์ผ๋ ๋ฐํ์์ ์ธํ
ํ ์ ์๋๋ฐ, ์ด๋ Relay์๊ฒ ์ฐ๋ฆฌ์ GraphQL ์๋ฒ์ ์ด๋ป๊ฒ ์ฐ๊ฒฐํ ๊ฒ์ธ์ง์ ๋ํด ์๋ ค์ฃผ๋ ๊ฒ๊ณผ ๊ฐ๋ค.
์์ ์ฝ๋๋ฅผ ๋์ผํ๊ฒ ์ฌ์ฉํ๋, ์ถ๊ฐ์ ์ผ๋ก Relay Environment ๋ฅผ ์ ์ํ๋ค. ์ด๋ ์๋ฒ (Relay Network) ์ ์ ์ฅ๋ ์บ์๋ฅผ ์ด๋ป๊ฒ ํ์ฉํ ๊ฒ์ธ์ง์ ๋ํด ์บก์ํํ๋ ๊ฒ์ ์๋ฏธํ๋ค.
Copy // your-app-name/src/RelayEnvironment.js
import {Environment, Network, RecordSource, Store} from 'relay-runtime';
import fetchGraphQL from './fetchGraphQL';
// Relay passes a "params" object with the query name and text. So we define a helper function
// to call our fetchGraphQL utility with params.text.
async function fetchRelay(params, variables) {
console.log(`fetching query ${params.name} with ${JSON.stringify(variables)}`);
return fetchGraphQL(params.text, variables);
}
// Export a singleton instance of Relay Environment configured with our network function:
export default new Environment({
network: Network.create(fetchRelay),
store: new Store(new RecordSource()),
});
Step 5. Fetching a Query With Relay
Copy ...
import fetchGraphQL from './fetchGraphQL';
import graphql from 'babel-plugin-relay/macro';
import {
RelayEnvironmentProvider,
loadQuery,
usePreloadedQuery,
} from 'react-relay/hooks';
import RelayEnvironment from './RelayEnvironment';
const { Suspense } = React;
// Define a query
const RepositoryNameQuery = graphql`
query AppRepositoryNameQuery {
repository(owner: "facebook", name: "relay") {
name
}
}
`;
// ์ฑ์ด ์์ํ์๋ง์ ์ฟผ๋ฆฌ๋ฅผ ์ฆ์ ๋ก๋ํ๋ค.
// ์ค์ ์ฑ์์๋ ๋ผ์ฐํ
configuration์ ์ด๋ฅผ ์ค์ ํ๊ณ , ์๋ก์ด route๋ก ์ด๋ ์ ๋ฐ์ดํฐ๋ฅผ ํ๋ฆฌ-๋ก๋ํ๋ค.
const preloadedQuery = loadQuery(RelayEnvironment, RepositoryNameQuery, {
/* query variables */
});
// ํ๋ฆฌ๋ก๋๋ ์ฟผ๋ฆฌ๋ฅผ ์ฝ๋ ์ด๋ ์ปดํฌ๋ํธ๋ `usePreloadedQuery`๋ฅผ ์ฌ์ฉํ๋ค.
// - ์ฟผ๋ฆฌ๊ฐ ์คํ ์๋ฃ๋๋ฉด, ์ฟผ๋ฆฌ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํดํ๋ค.
// - ์ฟผ๋ฆฌ๊ฐ ์์ง ํ๋ฉ ์ค์ด๋ฉด, Suspend ํ๋ค. ์ด๋ ๋ถ๋ชจ ์ปดํฌ๋ํธ ์ค ๊ฐ์ฅ ๊ฐ๊น์ด ์์นํ fallback์ ๊ทผ๊ฑฐํ๋ค.
// - ์ฟผ๋ฆฌ๊ฐ (๋ฐ์ดํฐ ํจ์นญ์) ์คํจํ๋ฉด, ์คํจ ์๋ฌ๋ฅผ ๋์ด๋ค.
function App(props) {
const data = usePreloadedQuery(RepositoryNameQuery, props.preloadedQuery);
return (
<div className="App">
<header className="App-header">
<p>{data.repository.name}</p>
</header>
</div>
);
}
// ์ App ์ปดํฌ๋ํธ๋ ์ด๋ป๊ฒ Relay Environment์ ์ ๊ทผํ ์ง์ ๋ํ ์ ๋ณด๊ฐ ์์ด์ผ ํ๊ณ ,
// Suspend ๊ฒฝ์ฐ๋ฅผ ์ํ fallback์ ์ค์ ํด์ผ ํ๋ค.
function AppRoot(props) {
return (
<RelayEnvironmentProvider environment={RelayEnvironment}>
<Suspense fallback={'Loading...'}>
<App preloadedQuery={preloadedQuery} />
</Suspense>
</RelayEnvironmentProvider>
);
}
export default AppRoot;
preloadQuery
์ฌ์ ์ ์ ์ํ RelayEnvironment์ RepositoryNameQuery, ์ฟผ๋ฆฌ ๋ณ์(args)๋ฅผ ์ ๋ฌํ๋ค.
AppRoot
<RelayEnvironmentProvider>
์ ํ์ฌ Relay Environment ์ธ์คํด์ค์์ ์ํต ๋ฐฉ์์ child ์ปดํฌ๋ํธ์ ์ ๋ฌํ๋ค.
<Suspense>
๋ child๊ฐ suspendํ ๊ฒฝ์ฐ์ fallback์ ์ง์ ํ๋ค.