코드네임 :

React - HTTP 요청 보내기 (ex. 데이터베이스 연결) 본문

👥Club/☁️9oormthon univ☁️

React - HTTP 요청 보내기 (ex. 데이터베이스 연결)

비엔 Vien 2025. 5. 8. 12:07

리액트 앱을 직접적으로 데이터베이스에 연결하는게 X

 

endpoint 라는 백엔드 API 사용

: 어떤 요청이 가능한지 통제 가능 (특정 요청만 받는 URL)

 

뭐야? 둘다 안되는데

뭐지,,, 계속 해도 안되는데...

 

일단 해라

 

 

places 데이터가 초기에 준비 X라면 우선 컴포넌트를 데이터 없이 렌더링해야하고 그 다음 데이터 준비됐을때 업데이트 해야함

 

빈 배열을 초기값으로 시작

import {UseState} from 'react';
import Places from './Places.jsx';
import { use } from 'react';

export default function AvailablePlaces({ onSelectPlace }) {
  const [availablePlaces, setAvailablePlaces] = useState([]);

  return (
    <Places
      title="Available Places"
      places={availablePlaces}
      fallbackText="No places available."
      onSelectPlace={onSelectPlace}
    />
  );

 

 

HTTP요청을 클라이언트 쪽 플젝에 보내는 방법, fetch()

: HTTP 요청을 다른 서버들로 보내는데 사용됨

//GET http://localhost:8000/places 요청을 서버로 보냄
fetch('http://localhost:8000/places')

//funcion이 비동기 async으로 실행될 경우에만

const response = await fetch('http://localhost:8000/places');
//여기서 places란 데이터 받고 백엔드 파일에 저장하는 경로




fetch('http://localhost:8000/places')
  .then((response) => { //.then()은 서버로부터의 응답을 받았을 때 실행됨
    return response.json(); // 서버 응답을 JSON으로 파싱
  })
  .then((resData) => { //.then()은 위에서 파싱된 JSON 데이터를 받을 때 실행됨
    setAvailablePlaces(resData.places); // 받은 데이터 중 places 값을 상태에 저장
  });
  // ⚠️컴포넌트가 리렌더링 될 때마다 계속 fetch 요청이 반복됨
  
  // ⬇️
  
  // 처음 렌더링될 때)만 fetch 실행됨
  import { useEffect } from 'react';
  
  useEffect(() => {
  fetch('http://localhost:8000/places')
    .then((response) => response.json())
    .then((resData) => {
      setAvailablePlaces(resData.places);
    });
}, []); // []로 리렌더링 될떄마다 fetch가 반복되지 않도록


//주로 사용되는 방법
//컴포넌트가 처음 화면에 나타날때 요 비동기 함수 실행하여 백엔드에서 /places 데이터를 가져오고 그걸 상태값으로 저장후 화면에 렌더링할수 잇게
useEffect(() => {
  async function fetchPlaces() {
    const response = await fetch("http://localhost:8000/places");
    const resData = await response.json();

    setAvailablePlaces(resData.places);
  }

  fetchPlaces();
}, []);

 

 

 

 

사용자 정의 에러 컴포넌트(Error.jsx)를 import할 때 주의할 점

import Error from './Error.jsx'; // ❌ 

import ErrorPage from './Error.jsx'; // ⭕️ 충돌 방지

 

 

데이터 fetching에 실패할수 있음

1. 애초에 요청 보내기가 실패 가능 (네트워크 연결 충돌 가능)

2. 백엔드에 성공적으로 전달되었으나 거기서부터 문제 시작

const [error, setError] = useState();

...

try {
  const response = await fetch("http://localhost:8000/places");
  const resData = await response.json();
  
  if (!response.ok) { //esponse.ok는 HTTP 응답 코드가 200~299 사이일 때만 true
    throw new Error('Failed to fetch places'); // 응답 실패 시 에러 발생
  }

   setAvailablePlaces(resData.places); //받아온 데이터 중 places 배열을 상태에 저장
   
} catch (error) {
  setError({message: error.message || 'Could not fetch places, please try again later}); // 에러가 발생했을 때 상태에 저장
				//혹시 error.message가 없을 수도 있으니까 || '기본 메시지' 로 대체
}

 

 

Fetch된 데이터 반환

import {sortPlacesByDistance} from '../loc.js';


...

useEffect(() => {
  async function fetchPlaces() {
    try {
      const response = await fetch("http://localhost:8000/places");
      const resData = await response.json();

      if (!response.ok) {
        throw new Error('Failed to fetch places');
      }

      navigator.geolocation.getCurrentPosition((position) => {
        const sortedPlaces = sortPlacesByDistance(
          resData.places,
          position.coords.latitude,
          position.coords.longitude
        );

        setAvailablePlaces(sortedPlaces);
        setIsFetching(false);
      });

    } catch (error) {
      setError({
        message: error.message || 'Could not fetch places, please try again later'
      });
      setIsFetching(false); //데이터를 모두 처리한 후, 로딩 완료 표시
    }
  }

  fetchPlaces(); // useEffect 내부에서 async 함수 호출
}, []);

 

 

 

 

데이터를 가져오는 코드를 외부로 분리

//http.js

export async function fetchAvailablePlaces() {
    const response = await fetch("http://localhost:8000/places");
    const resData = await response.json();
    
    if (!response.ok) { 
      throw new Error('Failed to fetch places'); 
    }

    return resData.places;
}
import { sortPlacesByDistance } from '../loc.js';
import { fetchAvailablePlaces } from '../http.js';

...

try {
      const places = await fetchAvailablePlaces(); // 여기
     

      navigator.geolocation.getCurrentPosition((position) => {
        const sortedPlaces = sortPlacesByDistance(
          places,
          position.coords.latitude,
          position.coords.longitude
        );
        
        ...

 

 

 

POST요청으로 데이터 전송

//http.js

...
export async function updateUserPlaces(places) {
    const response = await fetch('http://localhost:3000/user-places', {
        method : 'PUT',
        body: JSON.stringify(places),
        headers: {
            'Content-Type' : 'application/json'
        }
    });

    const resData = await response.json();

    if(response.ok){
        throw new Error('Failed to update user data.');
    }

    return resData.message;
}




//App.jsx

...

export async function updateUserPlaces(places) {
    const response = await fetch('http://localhost:3000/user-places', {
        method : 'PUT',
        body: JSON.stringify(places),
        headers: {
            'Content-Type' : 'application/json'
        }
    });

    const resData = await response.json();

    if(response.ok){
        throw new Error('Failed to update user data.');
    }

    return resData.message;
}

 

 

 

 

최적의 업데이트 방법