본문 바로가기
항해99/실전 WIL | TIL

[TIL-021] React Lv4 과제(3) - useQuery 사용해보기 / 에러핸들링

by junvely 2023. 5. 3.

Today목표 : 05/02일 React Lv4 과제(3) - useQuery 사용해보기 / 에러핸들링


상세 페이지에서 직접 url을 변경했을 때 발생하는 문제

❗상세 페이지에서 posts 전역상태로 부터 props을 받아와 보여주지 않고, 직접 페이지 id값으로 데이터 통신하여 post 정보를 가져오는 이유 , 에러처리를 해야 하는 이유

 

문제상황

1. url 조작 시 전역 상태에서 데이터를 가져올 때 문제점  +  id에 맞는 데이터가 있을 경우

상세 페이지에서 url 직접 경로로 이동 시 해당 경로에 맞는 페이지가 있더라도, 페이지가 새로고침 되어 전역 상태값이 초기화 된어 데이터가 유실되므로 에러가 발생한다.

2. url 조작 시 id에 맞는 데이터가 없을 경우의 문제점

해당 id에 맞는 데이터 값이 없을 경우 jsx문에서 렌더링할 데이터가 없어 에러가 발생한다. 사용자가 어떤 값을 입력하든 모든 값이 있을 수 없기 때문에 에러 발생을 막고, 그에 해당하는 페이지 처리를 해줘야 한다.

 

해결방법

1. *에러 처리 : id값에 해당하는 데이터가 없을 경우 post를 렌더링하지 않게 하여 에러가 발생하지 않게 막고, 에러 문구를 보여주도록 처리하였다.

 {!post ? (
        <StFlexCenter>
          <ErrorMessage>❗페이지 정보가 없습니다.</ErrorMessage>
        </StFlexCenter>
      ) : (
        <>
          <StPositionSec position={true}>

 

2. 전역 상태인 posts의 값이 초기화 되기 때문에 전역 데이터가 소실 되므로, 이를 방지하기 위해 직접 데이터 통신을 하여 데이터를 가져와 사용하도록 하였다.

function PostPage() {
  const dispatch = useDispatch();
  const { id } = useParams();
// 전역상태에서 id값으로 가져오지 않고, 직접 데이터 통신
  const getPostData = async () => {
    const data = await getPostAxios(id);
    dispatch(setPost(data)); //post reducer에 저장
  };

❗상세 페이지에서 *에러 처리를 해주어야 하는 이유

이와 같이 url id값에 의존하여 데이터를 가져올 경우, url 직접 경로로 이동 시 id값에 해당하는 데이터가 없으면 렌더링에서 데이터를 가져올 수 없어 에러가 발생한다. 사용자가 어떤 값을 입력하든 모든 값이 있을 수 없기 때문에 jsx문에서 에러 발생을 막고, 그에 해당하는 페이지 처리를 해줘야 한다. => 전역 상태값이 유실되었을 때, id값에 맞는 데이터가 없을 때 발생했다.

 

 

Posts와 post를 모두 전역상태로 관리해야 하는 이유 

❗Posts 전역 상태에서 받아온 Post 데이터로 하위 컴포넌트에 Props으로 직접 전달하지 않고, Post reducer를 따로 두어 전역 상태로 관리하는 이유

// 상세페이지 하위 컴포넌트 => PropsSlider에서 상태값 가져오기
function Modify({ modalToggle }) {
  const post = useSelector((state) => state.postSlice.post);

=> Props으로 전달도 물론 가능하지만, 그렇게 되면 

1. 가독성 : 코드 복잡도가 증가할 수록 중복 코드가 발생하고, 가독성이 좋지 않다.

2. Props dilling : Posts 전역 상태 변경 시 모든 참고하는 컴포넌트들 리렌더링 + 부모 컴포넌트 리렌더링 시 자식 컴포넌트도 리렌더링 등 Props드릴링에 의한 불필요한 렌더링 + 유지보수가 어렵다. 이를 방지하기 위해 Post reducer를 따로 두면 해당 state 변경 시에만 리렌더링 되어 불필요한 렌더링을 방지하고, 성능 향상을 향상시킬 수 있다.

=> PostPage의 Post 컴포넌트는 Post정보를 props으로 전달 받는데, 이유는 PostPage에서 Post 상태값이 정의되기 전에 그 상위 페이지인 PostsPage에서 먼저 사용되기 때문이다. 이 때는 아직 Post 상태 값이 없기 때문에 props으로 데이터를 전달받도록 하였다.

// post reducer에 값이 들어오기 전에 posts 컴포넌트에서 사용되기 때문에 props으로 전달받는다.
function Post({ post, width, isActive }) {
  const navigate = useNavigate();

 

 

 

custom Hook 사용 시 값을 초기화 하는 방법

❗custom Hook 사용 시 input값을 모두 받아 데이터를 전송 후, 값 초기화 하는 방법

=> reset을 추가해서 export 해주었다.

import { useState } from "react";
import { v4 as uuidv4 } from "uuid";

let today = new Date();

const initialState = {
  id: uuidv4(),
  userName: "Master",
  title: "",
  contents: "",
  imgURL: "",
  date: today.toLocaleDateString(),
};

export const usePost = () => {
  const [post, setPost] = useState(initialState);

  const handler = (e) => {
    const { name, value } = e.target;
    setPost({ ...post, [name]: value });
  };

  const reset = () => {
    setPost(initialState);
  };

  return [post, handler, reset];
};

 

 

development 환경에서만 redux devtool이 활성화 되도록 처리

 

[React] Redux Dev Tools, Development server에서만 실행되게 설정하기

Redux Dev Tools는 디버깅에 매우 유용한 기능이지만 Redux 내 유저에게 공개되어서는 안되는 정보가 담겨있을 수 있어 배포 버전에서는 사용을 제한해야하는 경우가 있다. 이 때 아래와 같이 사용한

velog.io

 

 

 

useQuery 사용시 주의할 점

1. useQuery의 두번째 인자, 비동기 함수에 매개변수를 보낼 경우

❗ 다음과 같이 보내게 되면 함수를 즉시 호출하는 것이다. => Missing queryFn Error 발생

  const { isLoading, isError, data } = useQuery("todo", getPostAxios(id));

해결방법 : 콜백 함수로 전달

  const { isLoading, isError, data } = useQuery("todo", () => getPostAxios(id));

 

2. mutation.mutate( 인자 )는 반드시 한개여야 한다. 아니면 에러 발생

mutation.mutate( 인자 )는 반드시 한개여야 한다. 아니면 에러 발생 => 한 개로 수정하여 해결

  const handleClickSaveUpdatePost = () => {
    if (formValidation()) {
      mutation.mutate(id, newPost); // 인자 2개를 주었다가 에러 발생
      resetPost(resetState); 
      modalToggle(); 
      alert("수정되었습니다!");
    }
  };

mutation.mutate( 인자 )는 반드시 한개여야 한다. 아니면 에러 발생

1. 인자는 반드시 한 개의 변수 또는 객체여야 한다.

2. mutation.mutate(인자1, 인자2) → 오류

 

 

useQuery 비동기 상태관리로 리팩토링 / 에러 핸들링 

❗useQuery비동기 상태관리로 리팩토링하면서 에러 핸들링에 대해 고민했다.

GET요청시와 POST,DELETE,PATCH에 따른 에러 핸들링을 해줘야 했는데 페이지 처리를 해야 할지, alert 등과 같은 경고문을 띄워야 할지 등등이 고민됐다. 결국 내가 내린 결론은, GET같은 경우 데이터를 가져와서 페이지를 보여줘야 하는 경우가 많기 때문에 페이지 처리를 하였고, 그 밖에 삭제, 수정, 추가 등의 경우 서버에 요청하는 경우가 많기 때문에 경고문 등으로 처리되게 만들었다. 

GET 요청 시 페이지 처리는 다음과 같이 JSX리턴문에서 진행하였다.

{/* 에러 페이지 처리 */}
      {!data || isLoading || isError ? (
        <StFlexCenter>
          <ErrorMessage>
            {!data
              ? "❗Not Found :해당하는 페이지 정보가 없습니다."
              : isLoading
              ? "🔵 Loding . . ."
              : "❗Error : 서버 Error발생으로 인하여 데이터를 가져올 수 없습니다."}
          </ErrorMessage>
          <Footer />
        </StFlexCenter>
      ) : (

usequery가 정말 좋았던 점은 이렇게 loading과 error, data 처리 값을 알아서 반환해준다는 것이었다.. 리덕스와 JSON으로 완성 후에 리팩토링 해보니 코드양이 현저히 줄고 너무 쉽고 간편하면서도 개발자가 고민하는 부분들을 모두 케어해주는 느낌이었다. 지금까지 사용해본 Hook 중에 가장 유용한 것 같다.

그외 POST,DELETE,PATCH 요청 시 경고문 등의 에러 처리는 다음과 같이 진행하였다.

  const { isLoading, isError, data } = useQuery("post", () => getPostAxios(id));
  const queryClient = useQueryClient();
  const mutation = useMutation(updatePostAxios, {
    onSuccess: () => {
      resetPost(resetState); // usePost 초기화
      modalToggle(); // toggle 닫기
      alert("수정 성공!");
      queryClient.invalidateQueries("post");
    },
    onError: () => {
      alert("Error : 서버 에러 발생");
    },
  });

경고문 등으로 에러처리를 해주고 있기 때문에 페이지 처리를 따로 해주진 않았다.

 

다음은 오늘 공부한 useQuery를 간단히 정리한 포스팅이다.

 

[React] React query 사용해 보기

React query 리액트에서 상태 관리 라이브러리 중 하나로, 강력한 비동기 상태 관리를 지원한다. 리액트 쿼리의 기능은 다음과 같다. Backend agnostic: 백엔드에 종속되지 않음 Dedicated Devtools: 전용 개발

junvelee.tistory.com