Project : 의미없는 데이터 update는 그만~~ feat: useRef

최문길·2024년 1월 20일
0

project

목록 보기
6/17

final project에서 내가 맡은 부분은 사장님들의 물류 관리 관련된 링크를 카드 형태로 모아두는 platform page이다.


내가 생각한
비즈니스 로직은 이렇다.

platform card 등록

platform page는 사장님들이

  • 링크를 input창에 입력하고
  • 링크와 연관된 키워드를 추가할 수 있고
  • 이미지를 등록 | | 안 할 수 있다.


platform card 편집

편집하기를 눌렀을 때

  • 링크만 update
  • title만 update
  • 이미지가 있으면, 이미지 삭제만 update
  • 이미지가 없으면, 이미지만 update,

위 update list를 조합해서 , 변경 전과 후를 비교해서 변경 된 것들만 data base에 update를 하고 싶다.




이럴 때 변경전, 후에 값을 비교할 때 사용 할 수 있는 도구는

내가 생각했을 때 useRef 이다.

platform card를 클릭시 useRef에 정보를 담고, 수정과 관련된 state를 만들어

수정버튼을 누르면 ref에 정보와 수정state의 정보를 비교해 변경됨이 없으면 버튼 클릭시에 return 시켜주고 하나라도 있으면

그 하나의 값만을 update 시킨다.




우선 알아둬야 할 점은 내 platform card의 비즈니스 로직 형태는 2가지 case가 있다.

  1. 이미지가 있고, link_url, title 있는 경우

  2. 이미지가 없고, link_url , title 있는 경우


그리고

이미지는 storage에서 img를 저장하고 img url을 받아 platform table의 row에 img_url 이라는 colum으로 저장해서

데이터를 받아 NEXT JS에서 제공하는 Image component 의 src에 바인딩 하는 로직이다.

수정 할 때 분기 처리를 해줘야 하는데

img 같은 경우에는 supabase에서 img_url로 데이터를 받아서 타입이 string이고 수정 할 때 이미지는 File 타입이므로

비교 할 시점에서 예외 처리를 해주어야 한다.

위 사진과 같이 case 별로 정리 하고

로직을 구현 하였다.

export interface EditFormType {
  id: string;
  name: string;
  link_url: string;
  store_id: string | null;
  image_url?: string | null;
  file?: File | null; // editTarget state에서 image 업로드 할 경우, 쓰일 타입
  createdAt?: string;
}

const [isShowEditForm,setIsShowEditForm] =  useState(false)// 수정 버튼을 클릭하면 true 로 바뀝니다.
const preDataRef = useRef<EditFormType | null>(); // 이전 값을 담아두는 ref
const [editTarget, setEditTarget] = useState<EditFormType>({
  id: '',
  name: '',
  link_url: '',
  store_id: storeId!,
  image_url: preImage ?? null,
}); // 이전 데이터 값과 비교할 state

  
  // 수정 할 카드의 정보를 담는 useEffect입니다.
useEffect(() => {
  if (editRef.current) return;
  editRef.current = { ...editTarget };
  return () => {
    editRef.current = null;
  };
}, [isShowEditForm]);

위는 기본 필요한 로직이고


아래는 수정할 때 일어나는 함수 (main)이다.

const updatePlatForm = async (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const editData: EditFormType = {
      ...editTarget,
    };

    // object의 각 value 값을 비교해서 틀린 값만을 추출하기
    let comparedData = Object.entries(editData).reduce((acc, [key, value]) => {
      // 조금더 이해하기 위해 주석을 지우지 않았습니다.
      // for (const key in editRef.current) {
      //   if (editRef.current[key as keyof EditFormType] !== value) {
      //     acc[key] = value;
      //   }
      // }
      if (editRef.current![key as keyof EditFormType] !== value) {
        acc[key as keyof EditFormType] = value;
      }
      if (editRef.current!['image_url']) {
        acc['image_url'] = editRef.current!['image_url'];
      }

      return acc;
    }, new Object() as EditFormType);

    if (isEmptyObject(comparedData) && editRef.current?.image_url === preImage) return;
    // 나중에 refactoring하기
    comparedData.id = editData.id;
    comparedData.store_id = editData.store_id;
    comparedData.createdAt;

    // 기존이미지가 있고 이미지 변경 했을 때
    if (editRef.current?.image_url && comparedData.file) {
      comparedData.createdAt = moment().toISOString();
      // 기존 이미지 삭제
      await removePlatFormImage(editRef.current);
      // 새로운 이미지 업로드
      await uploadPlatFormImage(comparedData);
      const { publicUrl: image_url } = downloadPlatFormImageUrl(comparedData);
      comparedData = {
        ...comparedData,
        image_url,
      };
      const { file, createdAt, ...updateTarget } = comparedData;
      await updatePlatFormData(updateTarget as TablesInsert<'platform'>);
    }

    // 기존데이터에 이미지가 없을 때 이미지 등록을 할 때
    if (!editRef.current?.image_url && comparedData.file) {
      comparedData.createdAt = moment().toISOString();

      await uploadPlatFormImage(comparedData);
      const { publicUrl: image_url } = downloadPlatFormImageUrl(comparedData);
      comparedData = {
        ...comparedData,
        image_url,
      };
      const { file, createdAt, ...updateTarget } = comparedData;
      await updatePlatFormData(updateTarget as TablesInsert<'platform'>);
    }

    const { file, createdAt, ...updateTarget } = comparedData;
    await updatePlatFormData(updateTarget as TablesInsert<'platform'>);
    const { platform, error } = await fetchPlatForm(storeId!);
    setFecthDataList(platform);
    setIsShowEditForm(false);
  };



그런데 .. 여기서 하나 조건을 더 추가해줘야 한다.

수정 할 때 이미지만 삭제 할 때 실행 되는 조건문이 필요하다 .

    // 수정 할 때 이미지만 삭제 할 때 실행 되는 조건문
    if (!preImage && !comparedData.link_url && !comparedData.name) {
      await removePlatFormImage(comparedData);
      const { file, createdAt, ...updateTarget } = comparedData;
      await updatePlatFormData({ ...updateTarget, image_url: null } as TablesInsert<'platform'>);
      const { platform, error } = await fetchPlatForm(storeId!);
      setFecthDataList(platform);
      setIsShowEditForm(false);
      return;
    }


결과


const updatePlatForm = async (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const editData: EditFormType = {
      ...editTarget,
    };

    // object의 각 value 값을 비교해서 틀린 값만을 추출하기
    let comparedData = Object.entries(editData).reduce((acc, [key, value]) => {
      if (editRef.current![key as keyof EditFormType] !== value) {
        acc[key as keyof EditFormType] = value;
      }
      if (editRef.current!['image_url']) {
        acc['image_url'] = editRef.current!['image_url'];
      }

      return acc;
    }, new Object() as EditFormType);

    if (isEmptyObject(comparedData) && editRef.current?.image_url === preImage) return;
    // 나중에 refactoring하기
    comparedData.id = editData.id;
    comparedData.store_id = editData.store_id;
    comparedData.createdAt;

    // 기존이미지가 있고 이미지 변경 했을 때
    if (editRef.current?.image_url && comparedData.file) {
      comparedData.createdAt = moment().toISOString();
      // 기존 이미지 삭제
      await removePlatFormImage(editRef.current);
      // 새로운 이미지 업로드
      await uploadPlatFormImage(comparedData);
      const { publicUrl: image_url } = downloadPlatFormImageUrl(comparedData);
      comparedData = {
        ...comparedData,
        image_url,
      };
      const { file, createdAt, ...updateTarget } = comparedData;
      await updatePlatFormData(updateTarget as TablesInsert<'platform'>);
    }

    // 기존데이터에 이미지가 없을 때 이미지 등록을 할 때
    if (!editRef.current?.image_url && comparedData.file) {
      comparedData.createdAt = moment().toISOString();

      await uploadPlatFormImage(comparedData);
      const { publicUrl: image_url } = downloadPlatFormImageUrl(comparedData);
      comparedData = {
        ...comparedData,
        image_url,
      };
      const { file, createdAt, ...updateTarget } = comparedData;
      await updatePlatFormData(updateTarget as TablesInsert<'platform'>);
    }

    // 수정 할 때 이미지만 삭제 할 때 실행 되는 조건문
    if (!preImage && !comparedData.link_url && !comparedData.name) {
      await removePlatFormImage(comparedData);
      const { file, createdAt, ...updateTarget } = comparedData;
      await updatePlatFormData({ ...updateTarget, image_url: null } as TablesInsert<'platform'>);
      const { platform, error } = await fetchPlatForm(storeId!);
      setFecthDataList(platform);
      setIsShowEditForm(false);
      return;
    }
    const { file, createdAt, ...updateTarget } = comparedData;
    await updatePlatFormData(updateTarget as TablesInsert<'platform'>);
    const { platform, error } = await fetchPlatForm(storeId!);
    setFecthDataList(platform);
    setIsShowEditForm(false);
  };



분기처리와 예외 처리를 한 이유

user는

언제나 수정, 편집을 할 때 모든 것을 수정,편집하지 않기 때문이다.

0개의 댓글