[TIL] 내일배움캠프 React 과정 2023.01.10

Today I Learned

  • React Native 팀 프로젝트 진행

 


댓글 수정, 삭제 시 View->Modal로 수정

원래는 <View> 컴포넌트를 이용해서 버튼을 클릭했을 때 댓글 수정, 댓글 삭제 기능이 보이도록 구현했는데 크기가 너무 작아서 수정 삭제 버튼을 클릭하기가 힘들고 <Modal> 컴포넌트도 한번 이용해보고 싶어서 수정하기로 했다.

 

<Modal visible={isOpenModal} transparent animationType="slide" onRequestClose={() => setIsOpenModal(false)}>
  <BackBlur onPress={() => setIsOpenModal(false)}>
    <EditDeleteBox>
      <EditDeleteBtn onPress={setEdit}>
        <ToggleText>댓글 수정</ToggleText>
      </EditDeleteBtn>
      <EditDeleteBtn onPress={() => deleteMutate.mutate(comment.id,{onSuccess: () => queryClient.invalidateQueries("communityComments")})}>
        <ToggleText>댓글 삭제</ToggleText>
      </EditDeleteBtn>
    </EditDeleteBox>
  </BackBlur>
</Modal>

최상위 모달 안에 배경을 블러 처리하기 위해서 TouchableOpacity로 만든 BackBlur를 넣고 그 안에 댓글 수정 삭제 버튼을 보여주는 View 컴포넌트를 넣었다.

 

그리고 블러 처리된 배경을 눌렀을 때 모달이 사라지게 하는 기능을 구현하고 싶어서 원래 View로 만들었던 BackBlure를 TouchableOpacity로 변경해서 onPress 기능을 추가했다. BackBlur를 클릭하면 Modal 컴포넌트의 visible 속성이 false로 변경되면서 모달이 사라지게 된다.

 

<Modal onRequestClose={() => setIsOpenModal(false)}>

그리고 핸드폰 자체의 뒤로 가기 버튼을 누르면 모달이 사라지는 기능도 구현하고 싶어서  Modal 컴포넌트의 onRequestClose props를 이용했다.

  • The onRequestClose callback is called when the user taps the hardware back button on Android or the menu button on Apple TV. 

참고 https://velog.io/@hooray/RN-React-Native-뒤로가기-버튼-사용하는-방법

 

useMutation 사용하기

// 기존 코드
const editComment = async (id) => {
    await updateDoc(doc(dbService, "communityComments", id), {
      content: editContent
    });
    setIsEdit(false); 
};

<EditInput onSubmitEditing={() => editComment(comment.id)} />

기존에 firebase와 useState로만 구현했던 댓글 수정 기능을 useMutation을 붙여서 리팩토링해봤다!

 

// 수정한 코드
const { mutate: editMutate } = useMutation(editComment, {
    onSuccess: () => {
      queryClient.invalidateQueries("communityComments")
    }
});

<EditInput onSubmitEditing={() => editMutate(comment.id)} />

useMutation을 사용하면 TextInput에서 onSubmitEditing을 할 때 editComment 함수를 그대로 실행하는 게 아니라 mutate 함수를 실행해야 한다. mutate에 수정하고자 하는 댓글의 id를 넘기면 그것을 editCommnet가 인자로 받아서 firebase에서 댓글 하나를 삭제한다.

 

그런데 이것을 새로고침하지 않아도 실시간으로 업데이트 해주려면 onSuccess 경우에 invalidateQueries를 실행하도록 해야 한다. useQuery로 데이터를 불러올 때 지정한 "communityComments"라는 쿼리 키를 이용해서 invalidateQueries를 하면 해당 쿼리 키의 데이터가 무효화(?)되어서 댓글 수정이 반영된 새로운 데이터를 업데이트할 수 있다.

 

useMutation을 이해하기 위한 험난한 과정...🤢

// 댓글 삭제하기
  const deleteComment = (id) => {
    Alert.alert("댓글 삭제", "댓글을 정말 삭제하시겠습니다?", [
      {text: "취소",
      style: "cancel",
      onPress: () => {
        setIsOpenModal(false);
      }
      },
      {text: "삭제",
      style: "destructive",
      onPress: () => {
        setIsOpenModal(false);
        deleteDoc(doc(dbService, "communityComments", id));
      }}
])

const deleteMutate  = useMutation(deleteComment, {
    onSuccess: () => {
      setIsOpenModal(false);
      queryClient.invalidateQueries("communityComments");
    }
});

추가, 수정은 useMutation이 onSuccess 했을 때 invalidateQueries가 잘 실행되어서 새로고침하지 않아도 추가, 수정된 댓글이 바로 업데이트가 되었는데 이상하게 삭제만 invalidateQueries가 실행되지 않았다. 이 문제의 원인을 찾기 위해서 튜터님이 거의 한 시간 가까이 함께 도와주셨는데 문제의 원인은 '언마운트'였다.

 

  • mutation.mutate의 후속 작업(callback)은 작업이 이루어지는 해당 컴포넌트가 unmount되면 (이 경우에선 모달이 닫히면) 정상 작동하지 않는다고 한다. (callbacks on mutate might not fire at all)
  • 그래서 모달을 닫는 closeModal을 callback에 배치하였고(기존에는 submit button 클릭하면 바로 닫히게 했었다), return문도 넣어서 invalidate 작업도 기다리게 해주었다.
  • 출처 https://velog.io/@raverana96/react-query-useMutation-후-invalidate해도-refetch가-동작하지-않는-문제

 

왜 댓글 수정의 경우에만 invalidateQueries가 실행되지 않았냐면 Alert 컴포넌트 내부에 댓글 삭제 버튼이 있는데 버튼을 클릭하면 삭제 함수가 실행되는 Alert 컴포넌트가 언마운트되기 때문에 invalidateQueries가 정상적으로 작동하지 않은 거 같다. 이 문제를 해결하기 위해서 Alert 컴포넌트가 언마운트된 후에 댓글을 삭제하는 함수를 실행하고 싶은데 아직 해결하지 못했다.


회고

useQuery 성공하고 useMutation까지 시도했다가 저녁 내내 튜터님과 문제 해결하며 고생했다. 그놈의 언마운트가 뭔지..! 이제 슬슬 프로젝트 마감에 대한 압박감이 느껴진다. 빨리 팀원들의 결과물을 합쳐서 완성본을 만들어나가야겠다. 그래도 같이 불만(?)을 토로하며 공감해줄 수 있는 동기들이 있어서 위로가 된다.😅

오늘의 성과: Modal 컴포넌트와 useMutation 사용해 보기!