๐์ํด๋ก ๋ฐ์ | ๋๊ด์  ๋ฐ์! ๐ฎ
๋๊ด์  ๋ฐ์์ด๋?
๋๊ด์  ์๋ต์ ์๋ฒ์ ์๋ต์ ๋ฐ๊ธฐ ์ ์ ํ๋ฐํธ์๋์ ์ ์ ์ ์ผ๋ก ๋ชจ๋ ๋ณํ์ ์๋ตํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ์ด๋ป๊ฒ ๋ณด๋ฉด ์ฐ๋ฆฌ๋ ๋ฏธ๋๋ฅผ ์์ธกํ๊ณ ์์ต๋๋ค!!!

Apollo์ ์บ์ฑ์ ํ์ฉํ์ฌ ๋ฐฑ์๋๊ฐ ๋ค์ ๋ณด๋ผ ์ ์๋ค๋ ๊ฒ์ ์๊ณ ์๋ ์บ์ ๊ธฐ๋ฐ์ ๋ค์ ์์ฑํ ์ ์์ต๋๋ค!
์บ์ ์ ๋ฐ์ดํธ
useMutation ํํฌ๋ฅผ ํธ์ถํ  ๋ ๋ ๋ฒ์งธ ์ธ์๋ ์ฌ๋ฌ ์ฝ๋ฐฑ์ ์ก์ธ์คํ  ์ ์๋ ์ต์
์ ์ฌ์ฉํฉ๋๋ค. onError , onComplete , variables , update ๋ฑ ๋คํธ์ํฌ ํธ์ถ ์ํ์ ๋ฐ๋ผ ์์
์ ์ํํ  ์ ์๋ ์์น์ฌ๊ธฐ๊ฐ ์บ์๋ฅผ ์กฐ์ํ ์ ์๋ ์๋ฒฝํ ์ฅ์์ ๋๋ค.
๋๊ด์  ๋ฐ์
๊ทธ๋ฌ๋ ๋จผ์ 
optimisticResponse ๋ฅผ ์ ๋ฌํด์ผ ํฉ๋๋ค. ์ด๊ฒ์ ์บ์์ ๊ธฐ๋กํ๊ธฐ ์ํด ์ ๊ณตํ  ์ ์ ์  ๋ฐ์ดํฐ์
๋๋ค.I usually separate where I declare my
variablesandoptimisticResponseto the mutation function. Like so.
const [post, postRes] = useMutation(CREATE_POST)
const submitHandler = (e) => {
    e.preventDefault()
    if (body.trim() !== '') {
    // Mutation Function  
    post({  
      variables: { body },
  // Here is where I like to declare what my 'Post' should look like  
        optimisticResponse: {
          createPost: {
            body,
            username: session!.username,
            createdAt: new Date().toISOString(),
            comments: [],
            likes: [],
            // You will have to assign a temporary Id. Like so
            id: 'Temp_ID',
            __typename: 'Post',
          },
        },
      })
    }
  }
NOTE: The temporary id you've assigned will be rewritten after the actual response comes back, assuming the network call is successful. So be wary of rerenders!
์ด์  ์บ์์ ์ฐ๊ธฐ ์ํด ํด๋น ํญ๋ชฉ
optimisticResponse์ ์ก์ธ์คํ  ์ ์์ต๋๋ค.update ์ฝ๋ฐฑ์ ์ฌ์ฉํ  ๊ฒ์
๋๋ค. mutate ํจ์๋ฅผ ์คํํ๋ ์๊ฐ ํธ๋ฆฌ๊ฑฐ๋ฉ๋๋ค.const [post, postRes] = useMutation(
    CREATE_POST,
    {
      // data is where we can access the optimisticResponse we passed in earlier 
      update: (cache, { data }) => {
        // Get the current cached data. 
        const existingPosts = client.readQuery({
         // The cached query key is the same as the name of the GQL schema
          query: GET_POSTS,
        })
        // Now we combine the optimisticResponse we passed in earlier and the existing data
        const newPosts = [data.createPost, ...existingPosts.getPosts]
        // Finally we overwrite the cache
        cache.writeQuery({
          query: GET_POSTS,
          data: { getPosts: newPosts },
        })
      }
    }
  )
GraphQL ์กฐ๊ฐ์ ์ฌ์ฉํ์ฌ ์ ๋ฐ์ดํธ
์ด์  ๊ฒฝ์ฐ์ ๋ฐ๋ผ ๋จ์ผ ํญ๋ชฉ์ ์ ๋ฐ์ดํธํด์ผ ํฉ๋๋ค. ์์ ์๋ฅผ ์ํํ๋ฉด ์๋นํ ๋น์ฉ์ด ๋ง์ด ๋ญ๋๋ค! ์ด๋ฅผ ๋ฌ์ฑํ๋ ค๋ฉด GQL Fragments์ ๋์์ด ํ์ํฉ๋๋ค.
GraphQL ์กฐ๊ฐ์ด๋ ๋ฌด์์ ๋๊น?
๋จ์ํ ์ฌ๋ฌ ์ฟผ๋ฆฌ์ ๋ณํ ๊ฐ์ ๊ณต์ ํ ์ ์๋ ๋ ผ๋ฆฌ ์กฐ๊ฐ์ ๋๋ค. GQL ์คํค๋ง์์ ๋ฐ๋ณต๋๋ ํจํด์ ์ถ์ถํ ์ ์์ต๋๋ค.
In this example most of my queries and mutations has this repeating schema for a Post. It would be better to put it on a fragment like this.
import { gql } from '@apollo/client'
export const PostFragment = gql`
  fragment PostParts on Post {
    id
    body
    createdAt
    username
    likes {
      username
    }
    comments {
      id
      body
      username
      createdAt
    }
  }
`
And apply it to every query and mutation that needs this. Like so.
// Spreading it like an object
export const COMMENT_POST = gql`
  ${PostFragment}
  mutation CommentPost($postId: ID!, $body: String!) {
    createComment(postId: $postId, body: $body) {
      ...PostParts
    }
  }
`
์ ๋ฐ์ดํธํ ํญ๋ชฉ์ ๊ฐ๋ณ์ ์ผ๋ก ์ ํํ ์ ์๋๋ก ์กฐ๊ฐ์ด ํ์ํฉ๋๋ค.
Fragment๋ฅผ ์ฌ์ฉํ์ฌ ์บ์ ์ ๋ฐ์ดํธ
 const [comment, commentRes] = useMutation(COMMENT_POST, {
    update: (cache, { data }) => {
      // We will take the post we wanted to update using readFragment. 
      const post = cache.readFragment({
        // From here we pass in the Id next to whatever you named
        // your cached data. Then the name of the fragment you've created.
        id: `Post:${data?.createComment.id}`,
        fragment: PostFragment,
      })
      // Then, we update it using writeFragment.
      cache.writeFragment({
      // Same as when you read the individual item
        id: `Post:${data?.createComment.id}`,
        fragment: PostFragment,
      // Updating the contents
      // In this example I'm just spreading the existing contents, then rewriting the comments with the data we passed from the optimisticResponse.
        data: {
          ...post,
          comments: data?.createComment.comments,
        },
      })
    }
  })
์ด๋ ๊ฒ ํ๋ฉด ์บ์๋ ์ ์ฒด ๋ฐ์ดํฐ๋ฅผ ๋ฎ์ด์ฐ๋ ๋์ ์ํ๋ ํญ๋ชฉ์ ํฐ์นํ ์ ์์ต๋๋ค!
์ด์  ์๋ฒ์ ๋ํ ํ์ ์ด ์๋ค๋ฉด ๊ฑฐ์ ์ฆ๊ฐ์ ์ธ UX๋ฅผ ๊ฐ๊ฒ ๋ฉ๋๋ค!

๊ฒฐ๋ก
๋น๋๊ธฐ ๋ฐ์ดํฐ๋ฅผ ๋ฐฐ์ฐ๊ธฐ ์์ํ์ ๋ ๋ก๋ฉ ์ ๋๋ฉ์ด์ ์ ๊ตฌํํ ๋ ๋๋ฌด ๋๋์ต๋๋ค. ๊ทธ๋ฌ๋ ๋น์ ์ ์ฌ์ฉ์๊ฐ ์ด๋์์๋ ๋ณผ ์ ์๊ณ UX๊ฐ ๋๋ฆฌ๊ฒ ๋๊ปด์ง๋๋ก ๊ท์ฐฎ๊ฒ ๋ง๋๋ ๊ฒฝ์ฐ.
UI์ ์ ์ ์ ์ผ๋ก ๋ฌด์ธ๊ฐ๋ฅผ ์ ๊ณตํ๋ฉด ์ฑ์ ๋ฐ์์ฑ์ ๋ง์ ์ฐจ์ด๊ฐ ์๊น๋๋ค. GraphQL์ฉ Apollo์ RestAPI์ฉ React Query๋ ๋ชจ๋ ์  ์ ํ์ด ๋ ๊ฒ์ ๋๋ค!
Reference
์ด ๋ฌธ์ ์ ๊ดํ์ฌ(๐์ํด๋ก ๋ฐ์ | ๋๊ด์  ๋ฐ์! ๐ฎ), ์ฐ๋ฆฌ๋ ์ด๊ณณ์์ ๋ ๋ง์ ์๋ฃ๋ฅผ ๋ฐ๊ฒฌํ๊ณ ๋งํฌ๋ฅผ ํด๋ฆญํ์ฌ ๋ณด์๋ค https://dev.to/imervinc/react-apollo-optimistic-response-4oghํ ์คํธ๋ฅผ ์์ ๋กญ๊ฒ ๊ณต์ ํ๊ฑฐ๋ ๋ณต์ฌํ ์ ์์ต๋๋ค.ํ์ง๋ง ์ด ๋ฌธ์์ URL์ ์ฐธ์กฐ URL๋ก ๋จ๊ฒจ ๋์ญ์์ค.
                                
                                
                                
                                
                                
                                ์ฐ์ํ ๊ฐ๋ฐ์ ์ฝํ
์ธ  ๋ฐ๊ฒฌ์ ์ ๋
                                (Collection and Share based on the CC Protocol.)
                            
์ข์ ์นํ์ด์ง ์ฆ๊ฒจ์ฐพ๊ธฐ
๊ฐ๋ฐ์ ์ฐ์ ์ฌ์ดํธ ์์ง
๊ฐ๋ฐ์๊ฐ ์์์ผ ํ ํ์ ์ฌ์ดํธ 100์ ์ถ์ฒ ์ฐ๋ฆฌ๋ ๋น์ ์ ์ํด 100๊ฐ์ ์์ฃผ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์ ํ์ต ์ฌ์ดํธ๋ฅผ ์ ๋ฆฌํ์ต๋๋ค