#6 모바일 청첩장 빌더 - serverState와 clientState 동기화

김병훈·2024년 3월 3일
0

bora-n-maria

목록 보기
6/7
post-thumbnail

TODO

1. update 로직 수정

client에서 직접 supabase로 업데이트 요청을 하지 않고, route로 이양하기
update할 때, 권한 체크하기

왜?

  1. client 사이드에 업데이트 로직까지 몰려있어, 코드 분리 차원
  2. supabase를 사용하지 않게 되었을 때, 수정을 용이하게 하기 위함
  3. update 과정에서 권한을 체크해야 하는 경우 등의 상황이 생길 때, 어떤 통신을 주고받았는지 클라이언트 단에 노출시키지 않기 위함

구조

action.tsx

export const updateTemplate = async (data) => {
  'use server';
  const url = '~~';
  await fetch(url, {
    method: 'PATCH',
    body: data
  }); // route로 요청보내기
  
  revalidateTag('template'); // 데이터 refetch
};

SubmitButton.tsx

const SubmitButton = () => {
  // ...
  const submit = await () => {
    // ...
    const data = {};
    await updateTemplate(data);
  };
};

route.ts

const PATCH = (req) => {
  // ...
  await checkUserUpdatePermission();
  await updateTemplateMeta();
  await updateTemplatePosts();
};

2. serverState와 clientState 동기화

업데이트 후, refetch한 serverState와 useState로 관리하던 clientState간의 동기화가 되지 않는 문제

동기화가 필요한 이유

현재 구조에서는 다음 플로우로 업데이트가 2번 일어났을 때, 예상했던 동작과 다르게 수행 됨.

(post를 추가) -> (첫 번째 업데이트) -> (refetch) -> (두 번째 업데이트)

post를 추가했을 때, clientState는 추가된 post의 id를 임시로 만들어서 관리를 한다.
업데이트를 수행했을 때, 임시 id는 제외하고 insert를 하게 되는데 이 post에 대해 새로운 id를 부여함.
그렇기에 refetch를 했을 때 가져오는 template의 post id와 clientState에서의 post id가 달라짐.

업데이트를 1번만 했으면, 크게 문제될 것은 아니지만 다시 업데이트를 했을 때 문제가 발생

아무것도 변경하지 않고, 두 번째 업데이트를 수행한다면
(예상 로직)
post에 대해서는 insert 없이, 기존 post에 대해서 update만 수행

(실제 로직)
이전 업데이트에서 추가되었던 post는 delete & insert 수행.
추가되었던 post에 대한 id를 서로 다르게 관리하고 있기 때문)

동기화를 어떻게 할 것인가?

  1. refetch가 일어나서, server에서 전달받은 template이 변경되었을 때 clientState를 변경된 데이터에 맞춰준다.
  2. clientState를 관리하는 컴포넌트의 key를 template 업데이트했을 때 변경하여, 리렌더링을 트리깅한다.
  3. 업데이트를 할 때, 동기화가 필요한 데이터(ex. insert)는 따로 clientState 동기화를 해준다.

나는 더 간단한 방식인 1번 방식으로 진행했음.
2번 방식은 동기화 때문에 하기에는 너무 과하다고 생각함.
3번 방식은 로직이 복잡해질 것

적용

// serverComponent
const Page = async() => {
  // ...
  return <InnerPage template={template} /> 
};

// clientComponent
const InnerPage = (template) => {
  const [posts, setPosts] = useState(template.posts);
  useEffect(() => {
    setPosts(template.posts);
  }, [template.posts]);
  
  // ...
};

TIL

없음.

profile
재밌는 걸 만드는 것을 좋아하는 메이커

0개의 댓글