client측에서만 사용하는 상태관리를 해야할 때가 있다. 따로 서버 측으로부터 데이터를 요청하는 것이 아니라, client 측에서 localStorage, cookie 등으로 관리를 해주어야 할 때가 있는데, Apollo Client에서는 이때 로컬 상태 관리를 직접 해주는 'local-only fields'를 제공한다!
apollographql - local-only fields 출처
https://www.apollographql.com/docs/react/local-state/managing-state-with-field-policies
최근에 사용자들의 게시글 노출 유무를 localStorage에 저장하여 게시글을 보여줄지 말지를 결정하는 업무를 진행한 적이 있는데, 이 때 알게 된 local-only fields라는게 넘 유용하고 신기해서 공유해보긔 ^-^*
예시를 들어보면,
나는 getCheckedPost 전체를 로컬로 관리해주기 위해 그 뒤에 @client 를 붙혀주었다.
Post.query.graphql
query CheckedPostQuery($userId: String!) {
checkedPost: getCheckedPost(userId: $userId)
@client {
pageIds
}
graphql/client-schema.graphql 내에서 따로 client용 쿼리들의 타입을 관리해준다.
type CheckedPost {
pageIds: [String!]
}
type Query {
getCheckedPost(userId: String!): CheckedPost
}
apollo client에서 제공하는 makeVar를 통해 변수를 만들 수 있는데, 이때 초기값을 설정하고, 어떤 식으로 해당 변수를 업데이트 시킬지를 만들어줄 수가 있다.
나는 localStorage에 유저와 해당 페이지 정보를 담아주고 싶어서 아래와 같이 만들어주었다.
import { makeVar } from '@apollo/client';
interface CheckedPost {
pageIds: string[];
}
const CHECKED_POST_KEY = 'CHECKED_POST';
const initialCheckedPostMapVar =
JSON.parse( window.localStorage.getItem(CHECKED_POST_KEY) ?? '{}'
) || {};
export const checkedPostMapVar = makeVar<
Record<string, CheckedPost>
>(initialCheckedPostMapVar);
export const updateCheckedPost = (
userId: string,
pageId: string
) => {
const current = checkedPostMapVar();
const updated = {
...current,
[userId]: {
pageIds: [...(current?.[userId]?.pageIds ?? ''), pageId],
},
};
window.localStorage.setItem(
CHECKED_POST_KEY,
JSON.stringify(updated)
);
checkedPostMapVar(updated);
};
apolloClient 파일 내에서 조작하고 싶은 데이터 형태로 만들어줌.
아래 getCheckedPost는 userId의 유무를 통해 값을 return할지 말지를 결정해주고 싶기 때문에 다음과 같이 작성하였다.
const cache = new InMemoryCache({
getCheckedPost: {
read(_, { variables }) {
if (!variables?.userId) {
return;
}
const checkedPostUserId = checkedPostMapVar()[
variables?.userId
];
// 게시글을 check했는지를 확인해주는 state 만들어주기
const isChecked = checkedOnboardingPinPostUserId?.classroomIds?.includes(
variables?.classroomId
);
return {...checkedPostUserId, isChecked,} ?? null;
},
},
써먹는게 젤 쉽죠잉
import { updateCheckedPost } from './CheckedOnboardingPinPostVar';
import {
useCheckedPostQuery,
} from 'common/apollo/graphql';
// 생략
const { data: postData } = useCheckedPostQuery({
variables: {
userId,
},
});
// 위의 useCheckedPostQuery로부터 받아온 데이터로,
// 게시글을 보여줄지 말지를 결정하는 변수
const hidePost = CheckedPinPost.isChecked
// 버튼에 onClick으로 달아주면, 자동으로
// localStorage에 바로바로 update 시킬 수 있다!
const handlePostClose = () => {
updateCheckedPost(userId, pageId);
};
암튼 사실 써먹느라 힘들었지만 넘 신기해서 기억하려고 적어두긔 ~!
graphql과 apollo client를 사용할 때, 로컬에서만 상태관리를 해주고 싶을 때 사용하면 좋은 local-only fields 였습니다!