UI(User Interface)
사용자와 정보기기나 소프트웨어의 화면 등 상호작용을 위한 장치
인터랙션
사용자가 제품이나 서비스를 사용하면서 상호간 작용하는 과정
예시로 자유게시판 상세보기에서 좋아요 버튼을 눌렀을 때를 생각해보자.
async function onClickLike() {
await likeBoard({
variables: { boardId: "6138031babd89b00293ae454" },
// refetch될 때까지 기다린다.
refetchQueries: [
{
query: FETCH_BOARD,
variables: { boardId: "6138031babd89b00293ae454" },
},
],
});
alert("좋아요를 클릭합니다.");
}
버튼을 클릭하고 사용자는 결과를 얻기위해 많은 과정을 걷쳐서 기다려야한다.
낙관적인 예측을 하는 UI이다. 서버로부터 받는 응답은 대부분 오류가 나지 않을 것이다. 성공적일 것이다라고 가정하고 사용자에게 성공했을 때의 결과를 바로 보여준다. 중요한 데이터에는 사용하면 안된다.
성공할거라고 예상했는데, 뒤늦게 서버에서 에러가 났다는 응답이 오면 조용히 원래 상태로 되돌린다.
import { gql, useMutation, useQuery } from "@apollo/client";
...
export default function OptimisticUIPage() {
const [likeBoard] = useMutation(LIKE_BOARD);
const { data } = useQuery(FETCH_BOARD, {
variables: { boardId: "6138031babd89b00293ae454" },
});
const onClickLike = () => {
likeBoard({
variables: { boardId: "6138031babd89b00293ae454" },
// optimisticResponse: graphQL에서 mutation을 할 때 제공하는 옵션.
optimisticResponse: {
likeBoard: data?.fetchBoard.likeCount + 1,
},
update(cache, { data }) {
cache.writeQuery({
query: FETCH_BOARD,
variables: { boardId: "6138031babd89b00293ae454" },
data: {
fetchBoard: {
// _id, __typename 반드시 적어야한다.
_id: "6138031babd89b00293ae454",
__typename: "Board",
likeCount: data.likeBoard,
},
},
});
},
});
};
return (
<>
<div>좋아요 갯수: {data?.fetchBoard.likeCount}</div>
<button onClick={onClickLike}>좋아요 올리기!!</button>
</>
);
}
likeBoard
함수가 실행 될 때, optimisticResponse
에 적은 내용이 apollo-client-cache
에 optimistic 버전으로 따로 저장된다.apollo-client
는 이를 알아차려 저장된 데이터를 가지고 연관된 컴포넌트들을 다시 렌더링한다. 이 때, 네트워크 요청이 필요없으로 사용자들에게 거의 바로 반영된다.apollo-client
는 기존의 optimistic
버전을 지우고 서버에서 받은 데이터를 저장한다.apollo-client
는 다시 이를 알아차리고 연관된 컴포넌트를 다시 렌더링 한다.