분류 Reactjs

React 데이터를 가져 오는 4 가지 방법

컨텐츠 정보

  • 조회 347 (작성일 )

본문

React는 집중된 컴포넌트 라이브러리입니다. 따라서 원격 데이터를 요청하는 방법에 대한 의견이 없습니다. 

HTTP를 통해 데이터를 요청하고 웹 API에 보내는 경우 고려해야 할 네 가지 옵션이 있습니다.


https://www.bitnative.com/2020/07/06/four-ways-to-fetch-data-in-react/ 


  1. Inline
  2. Centralized
  3. Custom Hook
  4. react-query/swr

참고 사항 :이 게시물에서 fetct로 HTTP 호출을 하고 있지만 패턴은 Axios와 같은 대안에도 적용됩니다. 또한 GraphQL을 사용하는 경우 Apollo와 같은 다른 좋은 옵션이 있습니다. 이 게시물에서는 기존 REST API를 호출한다고 가정합니다.


옵션 1 : 인라인 


가장 간단하고 가장 확실한 옵션입니다. React 컴포넌트에서 HTTP 호출을 작성하고 응답을 처리하십시오.


fetch("/users").then(response => response.json());

충분히 단순 해 보입니다. 그러나이 예제는 로드 상태, 오류 처리, 관련 상태 선언 및 설정 등을 간과합니다. 실제로 HTTP 호출은 다음과 같습니다.


import React, { useState, useEffect } from "react";

export default function InlineDemo() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetch(`${process.env.REACT_APP_API_BASE_URL}users`)
      .then(response => {
        if (response.ok) return response.json();
        throw response;
      })
      .then(json => {
        setUsers(json);
      })
      .catch(err => {
        console.error(err);
        setError(err);
      })
      .finally(() => {
        setLoading(false);
      });
  }, []);

  if (loading) return "Loading...";
  if (error) return "Oops!";
  return users[0].username;
}

몇 번의 호출로 간단한 앱의 경우 이 방법이 효과적입니다. 그러나 위의 국가 선언 및 useEffect는 상용구입니다. HTTP 호출을 많이 하는 경우 각각에 대해 약 20 줄의 코드를 복제하고 유지하고 싶지 않습니다. 인라인 호출은 추악합니다.


반드시 다루어야 할 모든 문제를 살펴보십시오.


  1. 로딩 상태 선언
  2. 오류 상태 선언
  3. 콘솔에 오류를 기록하십시오
  4. 응답이 response를 통해 200을 반환하는지 확인하십시오.
  5. 응답이 정상이면 응답을 json으로 변환하고 약속을 반환하십시오.
  6. 응답이 맞지 않으면 오류를 던지십시오
  7. 오류가 발생하더라도 로더가 숨겨 지도록 로드 상태를 마지막으로 숨 깁니다.
  8. useEffect가 한 번만 실행되도록 빈 종속성 배열을 선언하십시오.

그리고 이것은 아래에서 볼 수 있듯이 다른 많은 관련 문제를 무시하는 간단한 예입니다.


상용구를 줄이는 몇 가지 옵션을 살펴 보겠습니다.



옵션 2 : 중앙 집중식 폴더 


하나의 폴더에서 모든 HTTP 호출을 처리하면 어떻게 됩니까? 이 접근 방식을 사용하여 services라는 폴더를 만들고 그 안에 HTTP 호출을 만드는 함수를 배치합니다. 서비스는 가장 널리 사용되는 용어이지만 여기서는 "클라이언트"또는 "api"와 같은 다른 좋은 대체 이름이 많이 설명됩니다.


요점은 모든 HTTP 호출은 하나의 폴더에 저장된 일반 'ol JavaScript 함수를 통해 처리됩니다. 중앙화 된 getUsers 기능은 다음과 같습니다.


export function getUsers() {
  return fetch(`${process.env.REACT_APP_API_BASE_URL}users`).then(response =>
    response.json()
  );
}

다음은 getUsers 함수에 대한 호출입니다.


import React, { useState, useEffect } from "react";
import { getUsers } from "./services/userService";

export default function CentralDemo() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  useEffect(() => {
    getUsers()
      .then(json => {
        setUsers(json);
        setLoading(false);
      })
      .catch(err => {
        console.error(err);
        setError(err);
      });
  }, []);

  if (loading) return "Loading...";
  if (error) return "Oops!";
  return users[0].username;
}

통화 사이트를 크게 단순화하지는 않습니다. ?‍♂️ 주요 이점은 HTTP 호출을 지속적으로 처리한다는 것입니다. 아이디어는 다음과 같습니다. 관련 기능을 함께 처리하면 일관성 있게 처리하는 것이 더 쉽습니다. userService 폴더에 HTTP 호출을 수행하는 기능이 가득 차 있으면 일관성 있게 작업 할 수 있습니다. 또한 통화가 재사용 되면 이 중앙 위치에서 쉽게 전화를 걸 수 있습니다.


그러나 콜 사이트에는 여전히 많은 상용구가 있습니다. 우리는 더 잘할 수 있습니다.


옵션 3 – 사용자 정의 후크 


React Hooks의 마법으로, 우리는 마침내 반복 된 논리를 중앙 집중화 할 수 있습니다. 그렇다면 HTTP 호출을 간소화하기 위해 사용자 정의 useFetch 후크를 만드는 방법은 무엇입니까?


맞춤 후크는 다음과 같습니다.


import { useState, useEffect, useRef } from "react";
// This custom hook centralizes and streamlines handling of HTTP calls
export default function useFetch(url, init) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const prevInit = useRef();
  const prevUrl = useRef();

  useEffect(() => {
  // Only refetch if url or init params change.
    if (prevUrl.current === url && prevInit.current === init) return;
    prevUrl.current = url;
    prevInit.current = init;
    fetch(process.env.REACT_APP_API_BASE_URL + url, init)
      .then(response => {
        if (response.ok) return response.json();
        setError(response);
      })
      .then(data => setData(data))
      .catch(err => {
        console.error(err);
        setError(err);
      })
      .finally(() => setLoading(false));
  }, [init, url]);

  return { data, loading, error };
}

당신과 다를 수도 있지만,이 기본 레시피는 먼 길을 걸었습니다. 이 단일 후크는 모든 통화 사이트를 대폭 간소화합니다. 이 편리한 커스텀 훅으로 데이터를 가져 오는 데 필요한 코드가 얼마나 적은지 보십시오.


import React from "react";
import useFetch from "./useFetch";

export default function HookDemo() {
  const { data, loading, error } = useFetch("users");
  if (loading) return "Loading...";
  if (error) return "Oops!";
  return data[0].username;
}

많은 앱의 경우 이와 같은 사용자 지정 후크 만 있으면 됩니다. 그러나 이 후크는 이미 매우 복잡하며 다양한 우려를 생략합니다. 캐싱은 어떻습니까? 클라이언트의 연결이 신뢰할 수 없는 경우 다시 가져 오는 것은 어떻습니까? 사용자가 탭의 초점을 다시 맞출 때 새로운 데이터를 다시 가져 오시겠습니까? 중복 쿼리를 제거하는 것은 어떻습니까?


이 모든 작업을 수행하기 위해 이 사용자 지정 후크를 향상 시킬 수 있습니다. 그러나 기회는, 당신은 옵션 4에 도달해야 합니다 ...


옵션 4 – 반응 쿼리 또는 swr 


이 라이브러리들은 내가 고려하지 않았던 다양한 질문을 하도록 가르쳐 주었습니다.


React 쿼리 또는 swr을 사용하면 캐싱, 재시도, 포커스를 다시 가져 오기, 중복 쿼리 등이 처리됩니다. 맞춤 후크를 유지할 필요가 없습니다. 그리고 각 HTTP 호출에는 약간의 코드가 필요합니다.


import React from "react";
import { getUsers } from "./services/userService";
import { useQuery } from "react-query";

export default function ReactQueryDemo() {
  const { data, isLoading, error } = useQuery("users", getUsers);
  if (isLoading) return "Loading...";
  if (error) return "Oops!";
  return data[0].username;
}

팔렸어요 ? 대부분의 앱에서 이것은 오늘 내가 선호하는 옵션입니다. 전체 코드 샌드 박스는 다음과 같습니다.