React-Hook-Form에 대해 알아보고 적용해보기 2일차

김형빈·2024년 9월 24일

TIL

목록 보기
2/13

React-Hook-Form을 프로필 수정 페이지에 적용해보기

  • 프로필 수정 페이지 코드를 수정하려고 보니까 내가 보기에도 복잡한 코드에 처음 사용해보는 React-Hook-Form을 사용해야 되어서, 어떻게 시작해야 될지 감이 오지를 않았다...
  • 그렇다면 처음부터 다시 기능을 하나씩 구현해보자

첫 코드 작성

'use client';

const ProfileEditPage = () => {
  const params = useParams();
  const workspaceUserId = params.targetWorkspaceUserId as string;
  const { workspaceUser, updateWorkspaceUser } = useWorkspaceUser(workspaceUserId);

  const { register, handleSubmit, formState } = useForm({
    mode: 'onChange',
    defaultValues: {
      name: workspaceUser?.name,
      email: workspaceUser?.email,
      phone: workspaceUser?.phone
    }
  });

  const onSubmit = (value: FieldValues) => {
    console.log(value);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div className="flex flex-col border-2 border-black">
        <label htmlFor="name">이름</label>
        <input {...register('name')} type="text" />
      </div>
      <div className="flex flex-col border-2 border-black">
        <label>활동 상태</label>
        <input />
      </div>
      <div className="flex flex-col border-2 border-black">
        <label>이메일</label>
        <input {...register('email')} type="email" />
      </div>
      <div className="flex flex-col border-2 border-black">
        <label>전화번호</label>
        <input {...register('phone')} type="text" />
      </div>
      <button>수정 완료하기</button>
    </form>
  );
};

export default ProfileEditPage;

사라지는 defaultValue??

  • useForm을 사용해서 컴포넌트를 작성하였는데 바로 문제가 발생하였다.
  • 프로필 편집 버튼을 통해서 프로필 수정 페이지로 오게 되면 defaultValue가 존재하는데 새로고침을 하면 defaulValue가 자꾸 사라졌다.

원인은 defaultValue를 설정하는 시점에 데이터가 없다는 것!

위와 같은 현상이 발생하는 이유는 코드에 console.log로 데이터를 확인해보면 더 명확히 알 수 있다.

undefined이미지 데이터이미지

위와 같은 현상이 발생하는 이유

클라이언트 렌더링 어플리케이션에서는 사용자에게 화면에 콘텐츠를 표시하기 전에 최소 3번의 서버 왕복(roundtrips)이 필요하다.

1. |-> Markup (내용 없이 - 비어있는 index.html)
2.   |-> JS
3.     |-> Query

즉, JS를 가져올 때 Query에 대한 정보가 없기 때문에 undefined를 반환하고, Query를 가져올 때야 비로소 데이터에 대한 정보를 반환 할 수 있게 되는 것이다.

기존에 프로젝트에서 사용하였던 해결책

  • 실은 위의 문제는 React-Hook-Form을 사용하기 이전에도 코드를 작성하면서 겪었던 문제이다.
  • 이 때 문제를 해결하기 위해서 useEffect를 사용해서 객체에 값이 생긴다면 defaultValue 값을 업데이트 하는 방식을 사용하였다.
  useEffect(() => {
    setImageURL(profileImage);
    setName(setEmptyStr(workspaceName));
    setState(setEmptyStr(workspaceState));
    setEmail(setEmptyStr(workspaceEmail));
    setPhone(setEmptyStr(workspacePhone));
    setIsOpen(workspaceIsOpen ? workspaceIsOpen : false);
  }, [profileImage, workspaceName, workspaceEmail, workspacePhone, workspaceState, workspaceIsOpen]);

SSR을 사용한 더 좋은 해결책

1. |-> Markup (내용이 채워져있고, data가 초기화 되어있음)
2.   |-> JS
  • 서버 렌더링을 통해서 클라이언트 렌더링 과정을 위와 같이 변환할 수 있다.
  • 1번 과정에서 내용이 채워져 있고 data가 초기화 되어있는 html을 생성하기 위해서는 3가지 과정을 거친다.
    • 마크업을 생성/렌더링 하기 정에 해당 데이터를 미리 가져와야(prefetch)한다.
    • 데이터를 직렬화 가능한(serializable) 형식으로 dehydrate(data를 json 형태의 정적 데이터로 변경) 시켜 마크업에 포함(embed) 시킨다.
    • 클리아언트에서는 React Query 캐시로 해당 데이터를 hydrate하여 새로운 fetch를 클라이언트에서 추가적으로 할 필요가 없도록 해야한다.

Tanstack Query의 hydrate로 prefetch 구현하기

import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query';

interface ProfileParallelLayoutProps {
  home: React.ReactNode;
  params: {
    targetWorkspaceUserId: string;
  };
}

const ProfileParallelLayout = async ({
  children,
  home,
  params
}: StrictPropsWithChildren<ProfileParallelLayoutProps>) => {
  const queryClient = new QueryClient();

  await queryClient.prefetchQuery({
    queryKey: ['workspaceUser', params.targetWorkspaceUserId],
    queryFn: () => api.workspaceUser.getWorkspaceUser(params.targetWorkspaceUserId)
  });

  return (
    <>
      ...
       <HydrationBoundary state={dehydrate(queryClient)}>{children}</HydrationBoundary>
      ...
    </>
  );
};

export default ProfileParallelLayout;
  • 프로필 페이지 수정 레이아웃에 prefetchQuery를 통해서 데이터를 prefetch하고 HydrationBoundary의 state 속성을 통해서 queryClient를 dehydrate를 시켰다.
  • 이렇게 작성하면 클리아언트에서는 React Query 캐시로 해당 데이터를 hydrate하여 새로운 fetch를 클라이언트에서 추가적으로 할 필요가 없도록 한다.

결과

  • 새로고침을 진행하여도 defaultValue가 잘 반영되고, cosole.log를 찍어도 undefined가 찍히지 않는다!
profile
The secret of getting ahead is getting started.

0개의 댓글