[채찍피티] 3일차. 리엑트 프론트엔드에서 백엔드와 REST API 통신하기

채찍피티·2024년 4월 11일

채찍피티

목록 보기
5/8

저녁 일정이 있어서

멘티님께 일찍 시작해도 되는지 양해를 구하고 진행했다.

감사하게도 바로 응답해 주셔서 진행하였는데,

막상 멘티님의 코드를 보며 라이브 코딩을 하려니 어려웠다.

준비자료의 필요성을 절실히 느꼈다.


1. AXIOS 란?

node.js와 브라우저를 위한 Promise 기반 HTTP클라이언트이다.

리엑트에서는 GET, POST, PUT, DELETE 등의 메소드를 지원하기 때문에 쉽게 사용이 가능하다.

주로 백엔드 서버 단으로 API를 호출할 경우에 사용하며

config를 미리 지정해 놓고 인스턴스를 생성해 재사용성을 높일 수 있다.

1. GET - 전체 투두리스트 불러오기

axios에서 GET 호출은 get 메서드를 이용하여 쉽게 불러올 수 있다.

첫번째 인자로는 주소값을 넣어주면 된다.

	axios.get("/todos");

함수를 만들어 관리를 하게 된다면, 동기 호출이 가능하고, 재사용성이 높아진다.

자동으로 JSON 포멧으로 받아오게 되고, 결과값의 data 에 접근하면(Response.data) 원하는 데이터를 쉽게 가지고 올 수 있다.

자바스크립트는 비동기 처리를 하기때문에

api를 호출해서 결과값을 받아와 변수에 담는 코드가 있다 해도,

호출 후 결과값을 받아오는 시간을 기다리지 않고,

이미 다른곳에서 그 변수를 사용하기도 한다는 뜻이다.

즉, 결과값에 대한 안정성이 보장되지 않는다

그렇기 때문에 비동기 함수(async/await)을 사용하여 로직을 구성할 수 있다.

비동기 함수란? feat.ChatGPT

비동기 함수(async/await)는 JavaScript에서 비동기 코드를 작성하는 데 있어 가독성을 높이고, 동기 코드와 유사한 방식으로 비동기 처리 로직을 구성할 수 있게 해주는 매우 유용한 기능입니다. 특히 API 호출, 데이터베이스 쿼리, 파일 시스템 작업과 같이 시간이 소요되는 작업을 다룰 때 매우 효과적입니다.

비동기 함수의 기본
async 키워드는 함수 앞에 위치하며, 이 함수는 항상 프라미스(Promise)를 반환합니다. 함수 내부에서 return 문을 사용하면, 해당 값을 갖는 프라미스가 반환됩니다. 만약 함수가 명시적인 프라미스를 반환하지 않으면, JavaScript 엔진은 자동으로 함수의 반환 값을 프라미스로 감싸 반환합니다.
await 키워드는 async 함수 내부에서만 사용할 수 있으며, 프라미스의 결괏값을 기다립니다. await을 사용하면 프라미스가 처리될 때까지 함수의 실행을 일시 정지하고, 프라미스가 이행(resolve)되면 결과 값으로 재개합니다.

import axios from 'axios';

async function fetchTodoList() {
  try {
    const response = await axios.get('/todos');
    console.log(response.data); // 결과 값(response)확인
    return response.data; // 결과 값을 받아서 리턴
  } catch (error) {
    console.error('There was an error!', error);
  }
}

이렇게 미리 작성 해 둔 함수를 필요할 때 호출하여

원하는 값을 가지고 올 수 있다.

예를 들어 투두 리스트의 전체 배열값을 컴포넌트(TodoListComponent)가 처음 마운트 될 때

불러오고자 한다면 아래와 같이 코드를 작성해 볼 수 있다.

import React, { useState, useEffect } from 'react';
import axios from 'axios';

function TodoListComponent() {
  const [todoList, setTodoList] = useState([]); // 불러온 리스트를 담을 배열

  async function fetchTodoList() {
    try {
      const response = await axios.get('/todos'); 
      console.log("GET:" + response.data);
      return response.data; // 값을 기다렸다 반환
    } catch (error) {
      console.error(error);
    }
  }

  useEffect(() => {
    const fetchTodos = async () => {
      const data = await fetchTodoList();
      if (data) { // 데이터가 있을 경우에만 배열을 리스트에 담음
        setTodoList(data);
      }
    };

    fetchTodos();
  }, []); 
  
  // 리스트에 데이터가 없을 경우 로딩 화면 보여줌
  if (!todoList) return <div>로딩중...</div>; 

  return (
    <div>
      {todoList.map((todo) => (
        <div key={todo.id}>
          <h2>{todo.title}</h2>
          <p>{`Completed: ${todo.completed}`}</p>
        </div>
      ))}
    </div>
  );
}

export default TodoListComponent;

1-2. GET - 특정 투두리스트 불러오기

	axios.get(`/todos/${id}`);

id 값을 입력 받아 처리

async function fetchTodoById(id) {
  try {
    const response = await axios.get(`/todos/${id}`);
    console.log(response.data);
    return response.data; // 요청이 성공하면 응답 데이터 반환
  } catch (error) {
    console.error('There was an error!', error);
  }
}

컴포넌트에서 함수 사용 방법

  const data = await fetchTodoById(id);

2. POST - 투두리스트 생성하기

POST 의 경우 post 메소드를 사용하며 바디나 params 에 값을 담아 요청할 수 있다.

request body 에 값을 담아 보내려면 아래와 같이 작성해 주면 된다.

	axios.post("/todos", {
      title: title
    });

함수로 만들면

async function createTodo(title) {
  try {
    const response = await axios.post('/todos', {
      title: title
    });
    console.log(response.data);
  } catch (error) {
    console.error('There was an error!', error);
  }
}

사용 방법

리엑트에서 post 는 주로 form 을 이용하여 처리한다.

import React, { useState } from 'react';
import axios from 'axios';

function TodoCreateComponent() {
  const [title, setTitle] = useState('');

  const handleSubmit = async (event) => {
    event.preventDefault(); // 폼 제출 시 페이지 리로드 방지
    const data = await createTodo(title);
    console.log(data); // 생성된 Todo 항목 로그 출력
    setTitle(''); // 입력 필드 초기화
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={title}
        onChange={(e) => setTitle(e.target.value)}
        placeholder="투두리스트를 작성하세요.."
      />
      <button type="submit">추가</button>
    </form>
  );
}

3. DELETE - 투두리스트 삭제하기

	axios.delete(`/todos/${id}`);

4. PATCH - 투두리스트 수정하기(title,완료상태)

	axios.patch(`/todos/${id}`, {
      title: title,
      completed: completed
    });

React 너 왜 자꾸 오류가 나는 거야?

problem1. CORS 관련 에러

원인: CORS(Cross-Origin Resource Sharing) 문제는 웹 애플리케이션에서 다른 도메인의 리소스에 접근하려고 할 때 발생합니다. 기본적으로 브라우저는 보안상의 이유로 다른 출처(origin)의 리소스에 대한 요청을 제한합니다.

해결 방법:

서버 측에서 CORS 허용
프록시 서버 사용

problem2. 되는 것 같은데? 아닌가?

화면에 api 에러가 떴다가 시간이 지난 후 정상화 되며 데이터를 받아오는 경우

원인: API 호출이 비동기적으로 이루어지기 때문에, 데이터가 도착하기 전에 컴포넌트가 렌더링될 수 있습니다. 이로 인해 초기에는 에러 메시지가 표시되다가 데이터가 도착하면 정상적으로 데이터를 렌더링하게 됩니다.

해결 방법:

로딩 상태 관리: 데이터를 요청하고 있는 동안 '로딩 중...'과 같은 메시지를 사용자에게 보여주고, 데이터가 도착하면 해당 메시지를 데이터로 교체하는 방법을 사용합니다.
조건부 렌더링: 데이터가 있을 때와 없을 때의 UI를 분리하여 처리합니다. 이는 if 문이나 삼항 연산자를 사용하여 구현할 수 있습니다.

problem3. 왜 데이터에 있는 할일 title을 못가져오지?

원인:

비동기 데이터 처리 문제: 데이터를 비동기적으로 가져오는 과정에서, 실제로 데이터가 컴포넌트의 상태에 저장되기 전에 렌더링을 시도할 수 있습니다.
잘못된 데이터 경로 참조: API 응답 구조를 잘못 이해하여 데이터에 접근하는 경로가 잘못됐을 수 있습니다.
해결 방법:

상태 초기값 설정: 데이터가 로드되기 전에도 안전하게 접근할 수 있도록 상태의 초기값을 적절히 설정합니다. 예를 들어, 객체나 배열의 경우 빈 객체나 배열로 초기화할 수 있습니다.
조건부 렌더링: 데이터가 유효할 때만 해당 데이터를 렌더링하도록 하며, 그렇지 않은 경우 로딩 메시지나 대체 텍스트를 표시합니다.
응답 데이터의 경로 확인: 개발자 도구의 네트워크 탭을 사용하여 API 응답의 정확한 구조

출처: https://mingnol2.tistory.com/entry/React-axios-사용-시-proxy-설정-방법CRA-Vite-CORS오류-해결하기?category=1198630 [거북이 개발자:티스토리]

profile
어? 왜 되지?

2개의 댓글

comment-user-thumbnail
2024년 4월 15일

다음 일지 언제 나오나요? 현기증 날 것 같아요

1개의 답글