반응형

React fetch 사용법 Loading, Error, GET, POST

React에서 HTTP 요청을 보내는 방법은 크게 2가지라고 합니다. 첫째는 axios를 사용하는 것, 두 번째는 fetch를 사용하는 것. 이번 포스팅에서는 fetch를 사용하여 GET, POST를 시도해 보고, 그에 따른 Loading 처리하는 방법, Error처리하는 방법까지 다룹니다.

React fetch API loading, Error, GET, POST


React - backend 통신하는 방법

데이터를 얻고 싶다.

React App <-> Database server 

가장 빠른 방법은 데이터베이스와 직접 통신하는 방법일 텐데, 프런트에서 바로 데이터베이스에 접근하게 된다면, 일반 이용자들도 데이터에 접근 가능하기 때문에 반드시 피해야 합니다. 

React App <-> Backend App <->Database server

그래서 프런트와 백엔드는 REST API (Application Programming Interface)를 이용하여 서로 통신하고, 데이터를 주고받습니다. 이때 사용하는 것이 fetch API입니다. 


fetch API 1단계 GET

fetch는 기본 method 설정이 'GET'입니다. 

fetch('URL', { 설정하고 싶은 부분 method, body, header 등등}) //프로미스 return

fetch는 프로미스를 return 하기 때문에. then으로 response를 받아 원하는 추가 작업을 진행해 줍니다.

const [movies, setMovies] = useState([]);

function fetchMoviesHandler(){
    fetch('https://swapi.dev/api/films/')
    .then(response => {
        return response.json();
    })
    .then(data =>{
      const transformedMovies = data.results.map(movieData =>{
         return{
           id: movieData.episode_id,
           title: movieData.title,
           openingText: movieData.opening_crawl,
           releaseDate : movieData.release_date
         };

    setMovies(transformedMovies);
});
}

fetch API 2단계 async await 사용

1단계에서. then을 사용하니 callback함수 중첩이 많이 됐습니다. 이를 극복하기 위해서 then을 async, await로 바꾸었습니다. async, await를 사용하면 조금 더 깔끔한 코드로 변신할 수 있어요.

const [movies, setMovies] = useState([]);

async function fetchMoviesHandler(){ // <- async 추가
    const response = await fetch('https://swapi.dev/api/films/') //const response await 추가
    const data = await response.json(); //const data await 추가
    
    const transformedMovies = data.results.map(movieData =>{
         return{
           id: movieData.episode_id,
           title: movieData.title,
           openingText: movieData.opening_crawl,
           releaseDate : movieData.release_date
         };

    setMovies(transformedMovies);
});
}

fetch API 3단계 Loading 상태 추가

데이터를 받아오는데 시간이 많이 걸린다면? 화면에 Loading이라는 걸 알려주면 좋을 겁니다. 

useState를 활용하여 isLoading과 setIsLoading을 추가하고, fetchMoviesHandler() 시작 부분에 setIsLoading(true)로 로딩 상태를 업데이트했습니다. 물론 데이터를 다 받았다면 다시 setIsLoading(false)로 로딩 상태를 업데이트했어요. 

const [movies, setMovies] = useState([]);
const [isLoading, setIsLoading] = useState(false); //로딩 상태 추가

async function fetchMoviesHandler(){ 
    setIsLoading(true); //로딩하는 상태
    const response = await fetch('https://swapi.dev/api/films/') 
    const data = await response.json(); 
    
    const transformedMovies = data.results.map(movieData =>{
         return{
           id: movieData.episode_id,
           title: movieData.title,
           openingText: movieData.opening_crawl,
           releaseDate : movieData.release_date
         };

    setMovies(transformedMovies);
    setIsLoading(false); //not로딩 상태
});
}

//이런 방식으로 isLoading 활용
//{!isLoading && movies.length > 0 && <MoviesList movies = {movies}/>}
//{!isLoading && movies.length ===0 && <p>Found no movies</p>}
//{isLoading && <p>Loading...</p>}

fetch API 4단계 error 처리

만약에 데이터를 불러오는데, 서버 쪽에서 에러가 발생한다면? 사용자에게도 알려줘야 하겠죠? 

error, setError를 추가하고, try catch 구문을 추가하여 error를 처리할 수 있습니다. try문에 이전에 사용했던 부분을 복사 붙여 넣기를 하고, catch부분에서 error 메시지를 처리해 주면 됩니다.

const [movies, setMovies] = useState([]);
const [isLoading, setIsLoading] = useState(false); 
const [error, setError] = useState(null);//초기상태 에러 없음

async function fetchMoviesHandler(){ 
    setIsLoading(true); 
    setError(null); //에러 초기화
    
    try{ //async await를 사용하는 경우 try catch 구문으로 error처리
    const response = await fetch('https://swapi.dev/api/films/');
    if(!respons.ok){ //만약에 fetch과정에서 error가 발생했다면 error throw
      throw new Error('Something went wrong!');
    }
    const data = await response.json(); 
    
    const transformedMovies = data.results.map(movieData =>{
         return{
           id: movieData.episode_id,
           title: movieData.title,
           openingText: movieData.opening_crawl,
           releaseDate : movieData.release_date
         };

    setMovies(transformedMovies);
    setIsLoading(false); 
    }catch(error){ //catch error 
      setError(error.message); //setError에 에러 메세지를 저장
    }
    setIsLoading(false);// error가 발생하더라도, loading 상태는 처리되야함
});
}

//error 상태에 맞게 보여지는 부분 변경
//{!isLoading && movies.length > 0 && <MoviesList movies = {movies}/>}
//{!isLoading && movies.length ===0 && !error && <p>Found no movies</p>}
//{!isLoading && error && <p>{error}</p>}
//{isLoading && <p>Loading...</p>}

 fetch API 5단계 useCallback 사용

useCallback을 사용하여 fetchMoviesHandler를 필요할 때만 실행하는 방법입니다.

const [movies, setMovies] = useState([]);
const [isLoading, setIsLoading] = useState(false); 
const [error, setError] = useState(null);

//useCallback 사용 (async 유지)
const fetchMoviesHandler = useCallback(async () => { 
    setIsLoading(true); 
...
    }
    setIsLoading(false);
});
}, []); //useCallback문 마무리

//useEffect를 사용해서 즉각적으로 HTTP 요청을 보내기
useEffect(() => {
  fetchMoviesHandler();
}, [fetchMoviesHandler]);

fetch API 6단계 POST

이전 1~5단계가 GET와 관련된 부분이었다면 아래 코드는 POST를 이용하여 backend에 데이터를 전송하는 코드입니다. methond : 'POST'로 post라고 설정해 주고, body에는 JSON format으로 변형한 데이터를 보내고, headers도 설정해 줍니다. POST도 똑같이 프로미스를 반환하기 때문에 async, await를 사용해 줍니다. 

//POST Request
async function addMovieHandler(movie){
  const response = await fetch('URL', {
    method: 'POST', //default는 GET이기 때문에 POST로 따로 설정해줘야함
    body: JSON.stringify(movie), //array, list -> JSON format
    headers:{
      'Content-Type': 'application/json'
    }
  });
  const data = await response.json();
  console.log(data);
}

 

반응형