Loading...
본문 바로가기
👥
총 방문자
📖
0개 이상
총 포스팅
🧑
오늘 방문자 수
📅
0일째
블로그 운영

여러분의 방문을 환영해요! 🎉

다양한 개발 지식을 쉽고 재미있게 알려드리는 블로그가 될게요. 함께 성장해요! 😊

코딩 정보/React

[React] Query의 올바른 사용에 관해

by 꽁이꽁설꽁돌 2024. 11. 15.
728x90
반응형

목차

     

     

    먼저 react query를 들어가기 전에 useState의 남용 문제를 살펴보아야 한다.

    useState의 남용

    서버로부터 데이터를 불러오고(카테고리 리스트) 사용자가 카테고리를 필터링할 수 있도록 하는 코드

    import { fetchData } from "./api";
    import { computeCategories } from "./utils";
    
    const App = () => {
      const [data, setData] = React.useState(null);
      const [categories, setCategories] = React.useState([]);
    
      React.useEffect(() => {
        async function fetch() {
          const response = await fetchData();
          setData(response.data);
        }
    
        fetch();
      }, []);
    
      React.useEffect(() => {
        if (data) {
          setCategories(computeCategories(data));
        }
      }, [data]);
    
      return <>...</>;
    };

     

    사실 언뜻 보면 무엇이 잘못 되었지라는 생각이 든다.

    이런 용도로 useEffect가 나온거 아닌가?

     

    실제로 작동도 문제없이 잘된다. 하지만 다음과 같은 문제가 발생할 수 있다.

     

    버튼 클릭 시 data의 변경

    • 버튼 클릭으로 인해 data나 다른 상태가 변경되었다고 가정하면, 이로 인해 categories가 새로운 값으로 설정될 수 있다.
    • categories 상태가 특정 조건에서만 업데이트되도록 보장되지 않았으므로 의도와 다르게 값이 변경될 가능성이 있다.

    react-query의 데이터 재조회

     

    • react-query를 사용하면 네트워크가 재연결되거나 사용자가 탭을 포커스할 때 데이터가 자동으로 재조회된.
    • 재조회된 데이터가 data 상태를 업데이트하면, 이전과 동일한 로직에 의해 categories가 업데이트 된다.
    • 사용자가 변경한 Y 값이 X 값으로 덮어쓰여질 수 있어 의도하지 않은 상태가 된다.

     

    import { fetchData } from './api'
    import { computeCategories } from './utils'
    
    const App = () => {
       const [data, setData] = React.useState(null)
    -  const [categories, setCategories] = React.useState([])
    +  const categories = data ? computeCategories(data) : []
    
       React.useEffect(() => {
         async function fetch() {
           const response = await fetchData()
             setData(response.data)
           }
    
           fetch()
         }, [])
    
    -  React.useEffect(() => {
    -    if (data) {
    -      setCategories(computeCategories(data))
    -    }
    -  }, [data])
    
       return <>...</>
    }

     

    사실 위 내용은 useState보다는 useEffect에 대한 잘못된 이해로부터 시작되었다.

    useEffect는 state를 react 외부의 무언가와 동기화시키기 위해서 사용되어야 하는데 이를 서로 다른 두 개의 react state와 동기화 시키는 데 이용하는 것은 옳지 않다.

     

     

    react query의 남용

    react-query로 데이터를 불러오고 localstate에 저장하는 코드

    import React, { useState } from 'react';
    import { useQuery } from 'react-query';
    
    // 데이터 가져오는 함수
    const fetchData = async () => {
      const response = await fetch('https://api.example.com/data');
      if (!response.ok) {
        throw new Error('Network response was not ok');
      }
      return response.json();
    };
    
    const DataComponent = () => {
      // React Query로 데이터를 가져옴
      const { data, error, isLoading } = useQuery('data', fetchData);
    
      // 데이터를 상태에 저장
      const [dataState, setDataState] = useState(null);
    
      // 데이터가 로딩 중일 때
      if (isLoading) return <div>Loading...</div>;
    
      // 에러 처리
      if (error) return <div>Error fetching data</div>;
    
      // 데이터를 상태에 저장하는 함수
      const handleSaveData = () => {
        setDataState(data);
      };
    
      return (
        <div>
          <h1>Data Component</h1>
          <button onClick={handleSaveData}>Save Data to State</button>
          <div>
            {dataState ? (
              <pre>{JSON.stringify(dataState, null, 2)}</pre>
            ) : (
              <p>No data saved yet.</p>
            )}
          </div>
        </div>
      );
    };
    
    export default DataComponent;

     

    같은 맥락에서 react query에서 받아온 데이터는 state에 넣어서 사용해서는 안된다.

    그이유는 다음과 같다.

     

    useQuery로 받은 데이터를 로컬 상태에 넣는 경우, 이 로컬 상태는 React Query의 데이터 복사본이다.

    즉, 로컬 상태에 데이터를 저장하는 순간, React Query에서 관리하는 데이터와 로컬 상태는 분리된다.

    그 결과, React Query가 데이터를 업데이트할 때 그 변경 사항은 로컬 상태에는 자동으로 반영되지 않으므로 로컬 상태가 최신 상태를 유지하지 못한다.

     

    즉 위의 예시처럼 서로 다른 두 개의 state를 동기화 시키는 것과 비슷한 사용이다.

     

     

    결론

    만약 queryCache (queryClient.setQueryData)를 조작한다면 낙관적인 업데이트 또는 mutation 이후 백엔드에서 받은 데이터를 작성하는 경우여야만 한다. 백그라운드에서 다시 불러오는 데이터는 현재 데이터를 덮어씌울 수 있다는 점을 기억해야 한다.

     

     

    참고

    https://highjoon-dev.vercel.app/blogs/1-practical-react-query

     

    highjoon-dev

    highjoon's dev-log

    highjoon-dev.vercel.app

     

    반응형