์ฐ๋ฆฌ๊ฐ ์ด๋ค ๊ฒ์๊ธ์ ์ข์์๋ฅผ ๋๋ฅด๋ฉด ํ๊ฒฝ์ ๋ฐ๋ผ ์ข์์ ์๊ฐ ์ฌ๋ผ๊ฐ๋ ์๋๊ฐ ๋ค๋ฅด๋ค. ์ ๊ทธ๋ด๊น?
์ข์์๋ฅผ ๋๋ ์ ๋ ์ฒ๋ฆฌ ๊ณผ์
1. ๋ฐฑ์๋์ api ์์ฒญ, ๋ฐฑ์๋๋ DB์ ์์ฒญ
2. DB๋ ์ข์์ ์๋ฅผ ์ฌ๋ ค๋๊ณ ์ฌ๋ฆฐ ์ข์์ ์ ์๋ต
3. ๋ฐฑ์๋๋ ํด๋น ์๋ต์ ๋ค์ ๋ธ๋ผ์ฐ์ ์ ์๋ต
ํ๊ฒฝ์ ๋ฐ๋ผ ์ ๊ณผ์ ์ ์ํํ๋๋ฐ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆด ์๋ ์๋ค. ์ด๋ด ๋ Optimistic UI๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
Optimistic UI
๋ ์์ฒญ์ด ์๋ฒ์ ๋๋ฌํ๊ธฐ๋ ์ ์ ํ๋ฉด์ ๊ฐ์ ๋ฐ๊พธ๋ ๊ฒ์ด๋ค. ๊ทธ๋ฆฌ๊ณ ์์ฒญ์ด ์ฑ๊ณตํ๊ณ ๋๋ฉด ์๋ต์ผ๋ก ๋์์จ ๊ฐ์ ๋ค์ ํ๋ฉด์ ์
๋ฐ์ดํธํ๋ค. ์ด ๊ณผ์ ์์ ์ ์ ๋ ๋ณํ๋ฅผ ๋์น์ฑ์ง ๋ชปํ๋ค.
๋ง์ฝ ์ค๊ฐ์ ์์ฒญ์ด ์คํจํ๋ค๋ฉด ์ด์ ์ ๊ฐ์ ์๋ต์ผ๋ก ๋ณด๋ด์ฃผ๊ณ ์ด์ ์ ๊ฐ์ ํ๋ฉด์ ์
๋ฐ์ดํธ ํด์ค๋ค(๋กค๋ฐฑ
).
๋ฐ๋ผ์ Optimistic-UI
๋ ์ฑ๊ณต์ 99% ํ์ ํ๋ api์ ์ฌ์ฉํด์ผ ํ๋ค. ๋กค๋ฐฑ(์คํจ)๋์ด๋ ํฐ ์ด์๊ฐ ์๋ ๊ฒ์๋ง ์ฌ์ฉํ์!
์๋ฅผ ๋ค์ด, ๊ฒฐ์ ํ ์์ฌ ๊ธ์ก๊ณผ ๊ฐ์ ์ค์ํ api๋ ์๋์ ์๊ด์์ด ์ ๋๋ก ์ ์ฐจ๋ฅผ ๊ฑฐ์ณ์ ๋์ํด์ผ ํ์ง๋ง, ์ข์์์ ๊ฐ์ api๋ ์์์๋ฅผ ์จ์ ๋น ๋ฅด๊ฒ ์ฒ๋ฆฌํ ์ ์๋ค.
์๋ ๊ทธ๋ฆผ์ ์ข์์๋ฅผ ๋๋ ์ ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๊ณผ์ ์ ๋ํ๋ธ ๊ฒ์ด๋ค. (์: ๊ธฐ์กด ๋ฐฉ์, ์๋: Optimistic-UI)
์ข์์๋ฅผ ์ฌ๋ฆฌ๋ api์ธ, likeBoard ์์ฒญ์ Optimistic-UI
๋ฅผ ์ฌ์ฉํด๋ดค๋ค.
// import ๋ถ๋ถ ์๋ต
// ๊ฒ์๊ธ ์กฐํ api์์ ์ข์์ ๊ฐฏ์๋ง ๋ฝ์ ์ค๊ธฐ
const FETCH_BOARD = gql`
query fetchBoard($boardId: ID!){
fetchBoard(boardId: $boardId){
_id
likeCount
}
}
`
//์ข์์ ์นด์ดํธ ์ฌ๋ฆฌ๋ api
const LIKE_BOARD = gql`
mutation likeBoard($boardId:ID!){
likeBoard(boardId:$boardId)
}
`
export default function(){
const [likeBoard] = useMutation<Pick<IMutation,"likeBoard">,IMutationLikeBoardArgs>(LIKE_BOARD)
const { data } = useQuery(FETCH_BOARD,
{variables :{boardId : "๊ฒ์๊ธ ์์ด๋ ๋ฃ์ด์ฃผ์ธ์!"} })
const onClickLike = ()=>{
//likeBoard ๋ฎคํ
์ด์
ํจ์๋ฅผ ์คํํ๊ฒ ์ต๋๋ค.
void likeBoard({
variables :{
boardId : "๊ฒ์๊ธ ์์ด๋ ๋ฃ์ด์ฃผ์ธ์!"
},
// (๊ธฐ์กด ๋ฐฉ์) ์๋ต์ ๋ฐ๊ณ ๋ ํ ๋ฐ์์จ ์๋ต์ ๋ค์ fetch ํด์ค -> ๋๋ฆฌ๊ณ ํจ์จ์ ์ด์ง ๋ชปํจ(๋ฐฑ์๋์ ์์ฒญ์ ํ๋ฒ๋ ํด์ผ ํ๊ณ ๋ฐ์์ฌ ๋๊น์ง ๊ธฐ๋ค๋ ค์ผ ํจ)
//refetchQueries: [
// {
// query: FETCH_BOARD,
// variables : { boardId : "//๊ฒ์๊ธ ์์ด๋ ๋ฃ์ด์ฃผ์ธ์!" }
// }
// ]
// ์ตํฐ๋ฏธ์คํฑ UI -> ์บ์๋ฅผ ๋ฐ๊พธ๊ณ ์บ์๊ฐ์ ๋ฐ์์ค๋๊ฑธ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ๋ฐ๋ก ๋ฐ๊ฟ์ค
optimisticResponse: {
likeBoard : (data?.fetchBoard.likeCount || 0)+1
},
// apollo ์บ์ ์ง์ ์์ (๋ฐฑ์๋ ์บ์ X) -> ๋๋ฆฌ์ง๋ง ํจ์จ์ (๋ฐฑ์๋์ ์์ฒญ์ ์ํ์ง๋ง, ๋ฐ์์ฌ ๋๊น์ง ๊ธฐ๋ค๋ ค์ค์ผ ํจ)
update(cache,{data}){
// ์ด์ ์๊ฐ์๋ modify๋ฅผ ์ฌ์ฉํ์ง๋ง, ์ค๋์ writeQuery๋ฅผ ์ฌ์ฉํด๋ณด๊ฒ ์ต๋๋ค.
cache.writeQuery({
query : FETCH_BOARD,
variables : {boardId:'๊ฒ์๊ธ ์์ด๋ ๋ฃ์ด์ฃผ์ธ์!'}
//์ด๋ป๊ฒ ์์ ํ ๊ฒ์ธ์ง๋ ์๋์ ์ ์ด์ค
data: {
// ๊ธฐ์กด๊ฐ๊ณผ ๋๊ฐ์ด ๋ฐ์์์ผ ํจ
fetchBoard: {
_id : '๊ฒ์๊ธ ์์ด๋ ๋ฃ์ด์ฃผ์ธ์!',
__typename : "Board"
likeCount: data?.likeBoard
}
}
})
}
})
}
return(
<div>
<h1>์ตํฐ๋ฏธ์คํฑ UI</h1>
<div>ํ์ฌ์นด์ดํธ(์ข์์):{data.fetchBoard.likeCount}</div>
<button onClick={onClickOptimisticUI}>์ข์์ ์ฌ๋ฆฌ๊ธฐ!!</button>
</div>
)
}
optimistic-ui
๋ฅผ ์ ์ฉํ๋ฉด ์ปดํจํฐ ํ๊ฒฝ์ ์๊ด์์ด ์ ์ ๋ชจ๋๊ฐ ๋น ๋ฅธ ์๋น์ค๋ฅผ ์ด์ฉํ๋ ๊ฒ์ฒ๋ผ ๋ณด์ผ ์ ์๋ค. ์ํฉ์ ๋ฐ๋ผ ๋ฐ์ดํฐ๊ฐ ์ค์ํ์ง ์๊ณ ์คํจ ํ๋ฅ ์ด ๊ทนํ ๋ฎ์ ๊ฒฝ์ฐ ์ฌ์ฉํด์ฃผ๋ฉด ์ข๋ค!
์์ 8๊ฐ์ง ์ ๋ต์ ๋ฐ๋์ ์ฌ์ฉํด์ผ ํ๋ ๊ฒ์ ์๋๋ค. ์ํฉ๊ณผ ํ๊ฒฝ์ ๋ง๊ฒ ์ฅ๋จ์ ์ ์ ๊ณ ๋ คํด์ ์ฌ์ฉํ๋ฉด, ์ฌ์ฉ์์ ๋ง์กฑ๋๋ฅผ ๋์ด๋ ์ ๋ต์ด ๋ ์ ์๋ค.