ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ React ] 쉽고, 직관적인 React Query
    TIL 2024. 2. 22. 22:54
    728x90

     

     

    다른 서버와의 API 통신과 비동기 데이터 관리를 위해 Redux-thunk, Redux-Saga 등 미들웨어를 채택해서 사용했다.

    하지만 Redux-thunk, Redux-Saga 에는 다음과 같은 문제가 존재했는데

     

    1. 보일러 플레이트 : 코드량이 너무 많다.

    2. 규격화 문제 : Redux가 비동기 데이터 관리를 위한 전문 라이브러리가 아니다. ( 규격화 문제 )

     

    반면, React Query는 많은 강점을 가지고 있다. ( 쉽고, 책임에서 자유롭다 )

     

    1. 보일러 플레이트를 만들다가 오류가 날 일이 없다.

    2. 내가 만든 부분이 아니기에 잘못이 일어난들 내 잘못이 아니다.

    3. 사용방법이 기존 Redux-Thunk 대비 너무 쉽고 직관적이다.


    ✅ 리액트 쿼리의 주요 키워드 3가지

     

    🚩 Query

     

    - 어떤 데이터에 대한 요청을 의미한다.

    - axios의 경우 get 요청과 비슷하다. 

    const response = await axios.get(’http://localhost:3000/todos’)

     

    🚩 Mutation

     

    - 어떤 데이터를 변경하는 것.

    - 어떤 데이터라 하면, 데이터 그룹 그 자체를 의미한다.

    - 바뀐다는 것은 추가, 수정, 삭제를 의미. CRUD 중 CUD (create, update, delete)에 해당.

    - axios의 경우 post, put, patch, delete 요청과 비슷하다.

    axios.post(’http://localhost:3000/todos’., newTodo);
    axios.patch(`http://localhost:3000/todos/${id}`, {isDone: true});

     

    🚩 Query Invalidation

     

    - 위에서 보았던 Query를 invalidation 즉, 무효화 시킨다는 의미이다.

    - 무효화? 기존에 가져온 Query는 서버 데이터이기 때문에, 언제든지 변경이 있을 수 있다. 그렇기 때문에 '최신 상태가 아닐 수' 있다는 말이다. 그런 경우, 기존의 쿼리를 무효화 시킨 후 최신화 시켜야한다.

    - 이런 과정을 React Query에서는 알아서 해준다. 그 유용한 기능이 바로 Query Invalidation 이다.

     


     

    🛠️ React Query 설치 명령어

    yarn add react-query

     

     

    App.jsx

    import React from "react";
    import Router from "./shared/Router";
    import { QueryClient, QueryClientProvider } from "react-query";
    
    const queryClient = useQueryClient();
    
    const App = () => {
    
      return (
        <QueryClientProvider client={queryClient}>
          <Router />;
        </QueryClientProvider>
      );
    };
    
    export default App;

    - QueryClientProvider : 데이터를 읽어오는 기능(QueryClient)을 애플리케이션 전에 주입하는 API

     

    TodoList.jsx

    import React from "react";
    import { StyledDiv, StyledTodoListHeader, StyledTodoListBox } from "./styles";
    import Todo from "../Todo";
    import { __getTodosThunk } from "../../modules/todosSlice";
    import { getTodos } from "../../../api/todos";
    import { useQuery } from "react-query";
    
    function TodoList({ isActive }) {
      const { isLoading, isError, data } = useQuery("todos", getTodos);
    
      if (isLoading) {
        return <p>로딩중입니다....!</p>;
      }
    
      if (isError) {
        return <p>오류가 발생하였습니다...!</p>;
      }
    
      return (
        <StyledDiv>
          <StyledTodoListHeader>
            {isActive ? "해야 할 일 ⛱" : "완료한 일 ✅"}
          </StyledTodoListHeader>
          <StyledTodoListBox>
            {data
              .filter((item) => item.isDone === !isActive)
              .map((item) => {
                return <Todo key={item.id} todo={item} isActive={isActive} />;
              })}
          </StyledTodoListBox>
        </StyledDiv>
      );
    }
    
    export default TodoList;

    - const { isLoading, isError, data } = useQuery( "todos", getTodos );

     

    위 부분이 리액트 쿼리의 가장 큰 장점이라 할 수 있다. Thunk를 사용하면 isLoading, isError를 개발자가 직접 만들어야 했다면, 리액트 쿼리는 서버 데이터를 위한 표준을 제시하고 있기에 개발자에 따라 바뀔 염려가 없다.

     

    return문에 도착하기 전, isLoading/isError 에 따른 별도 처리를 통해 대기처리/오류처리를 쉽게 해결했다.

     

    Input.jsx

    ...
    import { addTodo } from "../../../api/todos";
    import { QueryClient, useMutation } from "react-query";
    ...
    
    
    function Input() {
    ...
    	const queryClient = new QueryClient();
    	
    	const mutation = useMutation(addTodo, {
    	  onSuccess: () => {
    	    // Invalidate and refresh
    	    // 이렇게 하면, todos라는 이름으로 만들었던 query를
    	    // invalidate 할 수 있어요.
    	    queryClient.invalidateQueries("todos");
    	  },
      });

    [ invalidation 과정 ]

    - Input.jsx 에서 값 입력으로 인해 서버 데이터가 변경됨

    - onSuccess가 일어나면 기존의 Query인 "todos"는 무효화

    - 새로운 데이터를 가져와서 "todos"를 최신화

    - TodoList.jsx를 갱신한다.

     

    따라서 리액트 앱은 최신 상태의 서버 데이터를 유지할 수 있게 된다.

    728x90
Designed by Tistory.