React.js Http request (feat.useEffect)

강정우·2023년 1월 9일
1

react.js

목록 보기
24/45
post-thumbnail

Fetch API

  • 앱으로 직접 데이터를 가져오거나 저장하고, 연결을 맺는 행위는 절대 해서는 안 된다.
    만약에 클라이언트 내부에서 DB에 직접 연결을 하게 된다면 또는 브라우저의 자바스크립트 코드를 통해 DB의 인증 정보를 노출시키는 행위이기 때문이다.

  • 잊지 말아야 할 것이, 브라우저에서 실행되는 모든 자바스크립트 코드는 브라우저뿐만이 아니라
    웹 사이트의 사용자들도 접근할 수 있다는 것이다.

  • JS를 사용하여 어떤 HTTP 요청이든 전달할 수 있다.
    예를 들어 패키지 중 axios라는 것도 있다. 어떤 자바스크립트 라이브러리를 사용하는가에 관계없이 HTTP 요청 전송을 하고 이에 대한 반응을 매우 간단하게 할 수 있는 패키지이다. 심지어 라이브러리 없이도 사용할 수 있다

  • 하지만 요즘은 Fetch API를 활용하는 브라우저 내장형이며 데이터를 불러오고 이름과는 다르게 데이터 전송도 가능하다. 이 API를 통해 HTTP 요청을 전송하고 응답을 처리할 수 있다.

사용법

const 함수Trigger = () =>{
  fetch("URL이름").then(res=>{
    return res.json();
  }).then(data=>{
    const 담고싶은_변수명 = data.results.map(아무거나=>{
      return{
        key1:아무거나.value1,
        key2:아무거나.value2,
        key3:아무거나.value3,
        key4:아무거나.value4
      }
    })
    setMovies(담고싶은_변수명);
  });
}

  • 첫번째 인수는 요청을 전송하려는 URL의 문자열이다.
    그리고 두 번째 인자는 JS 객체이다. 이 인자를 통해 다양한 선택사항을 지정할 수 있고 추가적인 헤더나 바디 또는 HTTP 요청 메소드의 변경 등을 할 수 있다.

  • 이 함수의 return값은 Promise 객체를 반환하는데 이 객체는 우리가 잠재적으로 발생할 수 있는 오류나 호출에 대한 응답에 반응할 수 있게 해준다
    그래서 .then() 메서드를 사용하여 비동기로 응답이 완료된 후 호출하여 .catch()로 오류를 처리하면 된다.

  • 응답 시 JSON으로 주고받는데 그 이유가 JSON은 데이터 교환에 사용하는 간단하지만 매우 유명한 형식이기 때문이다.

  • 그리고 JSON 데이터의 또 다른 이점은 자바스크립트로의 변환 작업이 필요하지만 그럼에도 불구하고 파일에서 자바스크립트 객체로의 변환이 매우 쉽다는 것이다 다행히 이 response(res) 객체에는 내장 메소드 .json()이 있어서 JSON response의 본문을 코드에서 사용할 수 있는 자바스크립트 객체로 자동 변환해준다.

  • 마지막으로 data가 바뀌었고 이것을 state로 관리하여 사용자 UI에 다시 랜더링해야하기 때문에 마지막에 setState로 관리하는 모습이다.

async, await

  • 앞서 언급한 것 처럼 Promise객체를 .then() chain으로 처리할 수 있지만 await과 async로도 처리할 수 있다.
async function 함수Trigger = {
  const res = await fetch("URL이름");
  const data = await res.json();
  const 담고싶은_변수명 = data.results.map(아무거나=>{
      return{
        key1:아무거나.value1,
        key2:아무거나.value2,
        key3:아무거나.value3,
        key4:아무거나.value4
      }
  });
  setMovies(담고싶은_변수명);
};
  • 이는 단순히 개발자로 하여금 보기 편하게 하기 위하여 설정된 사안이고 뒤에서는 해당 코드가 .then()으로 바뀌어 들어간다.

Http 오류 처리

  • 우리가 Http 전송을 하는 경우에도 무언가 잘못된 것이 있다면 오류가 발생할 수 있다.
    예를 들어 네트워크 연결이 없다던가 또는 오류 응답코드(http status)를 넘겨받는 오류들 말이다.

  • 어떤 백엔드 어플리케이션과 통신하든 간에 서로 다른 state들을 맞닥뜨릴 수 있으므로 처리 방법을 아는 것은 중요하다. request가 error를 받을 수도 있고 data를 받을 수도 있는데 이 data가 비어있을 수도 있다. 따라서 이런 여러 가지의 시나리오를 다룰 줄 알아야 한다.

  1. error state를 준비해 두어야 한다.
const [error, setError] = useState(null);
  1. 만약 코드를 async로 짰다면 try-catch문으로 만약 .then()으로 짰다면 .then().catch() 이런식으로 오류를 잡아주면 된다.
async function fetchMovieTrigger() {
  setIsLoading(true);
  setError(null);                // <= 여기 null을 한 번 더 초기화하는 이유는 전에있던 error를 없애기 위함이다.
  try {
    const response = await fetch("https://swapi.dev/api/films");
    console.log(response.status);
    if (!response.ok) {
      throw new Error("뭔가 심상치 않은데?!");
    }
    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 (err) {
    setError(err.message);
  }
  setIsLoading(false);
};
  1. 해당 오류 코드에 맞춰 내보낼 에러 코드를 만들어주면 된다.
let content = <p>영화가 없습니다.</p>;
if (movies.length>0) {content = <MoviesList movies={movies}/>}
if (error) {content = <p>{error}</p>}
if (isLoading) {content = <p>로딩중...</p>}

useEffect 훅으로 최초 로드 시 data 뿌려주기

  • 이게 가능한 이유는 HTTP 요청 전송은 일종의 sideEffct로 component의 state를 바꿔버리기 때문이다.

  • 이때 useEffect함수를 메인 컴포넌트의 함수 일부분으로 호출하지만 않도록 신경써주어야한다.
    앞서 배운것 처럼 만약 그렇게 하면 함수 호출이 되는 순간 state의 갱신이 발생하고 컴포넌트 함수가 재 렌더링, 재평가되면서 함수가 다시 호출되는 무한 루프가 발생하기 때문이다.

  • 위 사진 처럼 Trigger안에 Trigger가 들어가면 Trigger가 최신화 되었으니 의존성에 의하여 Trigger를 호출하고 Trigger가 호출되었으니 또 useEffect가 돌아고....

  • 그래서 의존성안에 아무것도 안 써넣는 것도 하나의 쉬운 방법이지만 이는
    "함수가 외부 state를 사용하게 되는데"
    이러면 의도치 않는 버그가 발생할 수 있기 때문에 가장 좋은 방법은 useCallback hook를 사용하는 것이다.

const fetchMovieTrigger = useCallback(async() => {
  // 초기화 구문들
  setIsLoading(true);
  ...
  try {
    ~~반환 로직~~
    // state 설정 구문들
    setMovies(transformedMovies);
    ...
  } catch (err) {
    setError(err.message);
  }
  setIsLoading(false);
}, []);

useEffect(()=>{
  fetchMovieTrigger();
}, [fetchMovieTrigger]);
  • 이때 function 구문으로 선언한 것이 아니라 더이상 hoisting이 되지 않으니 순서를 잘 지켜주어야한다.
profile
智(지)! 德(덕)! 體(체)!

0개의 댓글