🗂 Entire diretory structure
📁 common
📃 apollo-client.ts
📁 interfaces
📃 post.interface.ts
📁 styles
📃 index.ts
📃 layout.css
📃 typography.css
📁 components
📁 app
📃 app.component.css
📃 app.component.tsx
📁 header
📃 header.component.css
📃 header.component.tsx
📁 posts
📁 posts-form
📃 posts-form.component.css
📃 posts-form.component.tsx
📁 posts-grid
📃 posts-grid.component.css
📃 posts-grid.component.tsx
📁 posts-grid-item
📃 posts-grid-item.component.css
📃 posts-grid-item.component.tsx
📁 hooks/posts ✔
📃 useCreatePost.ts
📃 useGetPosts.ts
pages
📁 about
📃 about.page.css
📃 about.page.tsx
📁 home
📃 home.page.css
📃 home.page.tsx
📃 index.tsx
📁 common
📃 apollo-client.ts
import {ApolloClient, InMemoryCache} from '@apollo/client';
const client = new ApolloClient({
1️⃣ uri: 'https://graphqlzero.almansi.me/api',
cache: new InMemoryCache()
});
export default client;
📋 Memo(📃 apollo-client.ts)
1️⃣ uri
1. running GraphQl server that we request query
📁 interface -> 📃 post.interface.ts
1️⃣ export interface Post {
id: string,
title: string,
body: string
}
📋 Memo(📃post.interface.ts)
1️⃣ interface Post
1. interface of post
📁 components
import React from 'react';
import {NavLink} from 'react-router-dom';
import './header.component.css';
1️⃣ const Header: React.FC = () => {
return(
<header>
<nav>
<ul>
<li>
<NavLink to="/" >Home</NavLink>
</li>
<li>
<NavLink to="/about">About</NavLink>
</li>
</ul>
</nav>
</header>
);
}
export default Header;
1️⃣ const Header: React.FC
1. Component that provides Home and About Link.
📁 app -> 📃 app.component.tsx
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { ApolloProvider } from '@apollo/client';
import '../../common/styles';
import './app.component.css';
import Header from '../header/header.component';
import About from '../../pages/about/about.page';
import Home from '../../pages/home/home.page';
import client from '../../common/apollo-client';
const App : React.FC = () => {
return(
<ApolloProvider client={client}>
<Router>
<Header />
1️⃣ <Switch>
2️⃣ <Route path="/about">
<About />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</Router>
</ApolloProvider>
);
}
export default App;
📋 Memo(📃 app.component.tsx)
1️⃣ <Switch></Switch>
1. <Switch> exclusively renders route.
=> ([링크텍스트](https://reactrouter.com/web/api/Switch))
2️⃣ Difference between <Route> and <Link>
📌 First React Router library is made to achieve next two things
1. State's transitions are captured on URL bar
2. Ensure application starts from proper state through stateful URL address
📌 <Link> component changes route state in application

위 사진과 같은 component는 application이 /example state에 있음을 register 할 것이다.
nutshell 안에서 Link component는 state to state(page to page)의 변화에 responsible하다.

반면에 Route component는 route state를 기반으로 특정 component를 display하도록 switch처럼 작동하는 데 responsible하다.
📁 posts ➡ 📁 posts-grid ➡ 📁 posts-grid-item ➡ 📃 posts-grid-item.component.tsx
import { Post } from '../../../../common/interfaces/post.interface';
const PostsGridItem:React.FC<{post : Post}> = (1️⃣ {post} : {post:Post}) => {
return(
<div>
<p>{post.id}</p>
<p>{post.body}</p>
<p>{post.title}</p>
</div>
);
}
export default PostsGridItem;
📋 Memo(📃 posts-grid-item.component.tsx)
1️⃣ {post} : {post:Post}
1. destructuring assignment와 그것의 type 선언이다.
📁 posts ➡ 📁 posts-grid ➡ posts-grid.component.tsx
import React from 'react';
import { Post } from '../../../common/interfaces/post.interface';
import PostsGridItem from './posts-grid-item/posts-grid-item.component';
1️⃣ const PostsGrid:React.FC<{posts : Post[]}> = ({posts} : {posts : Post[]}) => {
return(
<div className="posts-grid">
{posts.map(post => (
<div key={post.id}>
<PostsGridItem post={post}/>
</div>
))}
</div>
);
}
export default PostsGrid;
📋 Memo(📃 posts-grid.component.tsx)
1️⃣ const PostsGrid:React.FC
1. 모든 Post를 <div>로 생성하는 component이다.
📁 posts ➡ 📁 posts-form ➡ 📃 posts-form.component.tsx
import React from 'react';
import {useForm} from 'react-hook-form';
import { useCreatePost } from '../../../hooks/posts/useCreatePost';
interface FormData {
title:string;
body:string;
}
>
const PostsForm: React.FC = () => {
1️⃣ const {register, handleSubmit} = useForm<FormData>();
const createPost = useCreatePost();
const onSubmit = handleSubmit(({title, body}) => {
createPost({ variables: { input: { title : title, body : body } } });
});
return (
<div className="posts-form">
<form onSubmit={onSubmit}>
<input type="text" name="title" ref={register} />
<textarea name="body" ref={register} />
<input type="submit" />
</form>
</div>
);
}
export default PostsForm;
📋 Memo(📃 posts-form.component.tsx)
1️⃣ const {register, handleSubmit} = useForm<FormData>();
1. ref로 register을 연결해서 input의 값을 subscribe 할 수 있다.
2. handleSubmit 안에서 실행되는 함수의 parameters로 subscribe되어 있는 input들의 값이 전달된다.
3. name attribute가 key로 작동하기 때문에 unique 해야한다.
📁 hooks/posts
📃 useGetPosts.ts
import {gql, useQuery} from '@apollo/client';
import {Post} from '../../common/interfaces/post.interface'
const GET_POSTS = gql`
1️⃣ query GetPosts($options : PageQueryOptions!){ # query 이름은 마음대로 변경이 가능하다.
✔ posts(options: $options) { #
✔ data { # 임의로 변경 불가능 한 곳
✔ id #
✔ title # ✔ 표시들은 schema에 맞춰서 작성해야한다.
✔ body #
} #
} #
}
`
export const useGetPosts = () : Post[] | undefined => {
2️⃣ const {data} = useQuery(GET_POSTS,{
variables:{ options: {paginate:{page:1, limit:10}}}
});
return data?.posts?.data;
}
📋 Memo(📃 useGetPosts.ts)
1️⃣ query GetPosts...

2️⃣ const {data} = useQuery(GET_POSTS,{
variables:{ options: {paginate:{page:1, limit:10}}}
});

📃 useCreatePost.ts
import {gql, useMutation} from '@apollo/client';
1️⃣ interface CreatePostInput {
variables : {
input : {
title:string;
body:string;
}
}
}
2️⃣ const CREATE_POST = gql`
mutation CreatePost($input: CreatePostInput!) {
🔰 createPost(input: $input){
id
title
body
}
}
`
export 3️⃣ const useCreatePost = (): ((createPostInput: CreatePostInput) => any) =>
{
const [createPost] = useMutation(CREATE_POST, {
4️⃣ update(cache, {data: {createPost}}) {
cache.modify({
fields:{
posts(existingPosts = []){
const newPostRef = cache.writeFragment({
data : createPost,
fragment: gql`
fragment NewPost on Post { // NewPost, Post 임의변경가능
id,
title,
body
}
`
});
return [...existingPosts, newPostRef]
}
}
})
}
});
return createPost;
}
📋 Memo(📃 useCreatePost.ts)
1️⃣ interface CreatePostInput
1. mutation 함수로 넘겨줄 data의 interface를 정의한다.
2️⃣ const CREATE_POST
1. GraphQL server로 보낼 mutation query이다.
3️⃣ const useCreatePost
1. mutation function을 return하는 함수이다.
4️⃣ update(cache, {data: {createPost}})
1. cache object that represents the Apollo Client cache.
This object provides access to cache API methods like readQuery,
writeQuery, readFragment, writeFragment and modify.
These methods enable you to execute GraphQL operations on the cache
as though you're interacting with a GraphQL server.
2. data는 result of mutation을 갖고 있다.
여기에서 createPost는 🔰 뒤에 createPost와 같은 것이다.
📁 pages
📁about -> 📃 about.page.tsx
import React from 'react';
import PostsForm from '../../components/posts/posts-form/posts-form.component';
const About:React.FC = () => {
return(
<div className="about">
<PostsForm />
</div>
);
}
export default About;
📁home -> 📃 home.page.tsx
import React from 'react';
import PostsGrid from '../../components/posts/posts-grid/posts-grid.component';
import {useGetPosts} from '../../hooks/posts/useGetPosts';
const Home:React.FC = () => {
const posts = useGetPosts();
return(
<div className="home">
1️⃣ <PostsGrid posts={posts || []}/>
</div>
);
}
export default Home;
📋 Memo(📃 home.page.tsx)
1️⃣ <PostsGrid posts={posts || []}/>
1. posts는 posts or [] 이다.