ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Django/React] 백엔드 프론트엔드 통신하기 (fetch)
    JavaScript/React 2023. 1. 25. 21:56
    728x90
    반응형

    데이터 fetch하기

    django에서는 시스템을 보호하고 있기 때문에 아무데서나 fetch를 해올 수 없기 때문에 이를 설정하기 위해 cors-headers를 설치할 필요가 있다.

     

     


     

    데이터를 fetch하기 위해서 먼저 django-cors-headers 설치하기

     

    그런데 django-cors-headers란?

    cors-headers는 특정 도메인에서 '나의 서버에서 브라우저로 fetch할 수 있는 사람'을 지정할 수 있게 해준다.

     

    1. 백엔드에 cors-headers를 설치해준다.

    python -m pip install django-cors-headers

    poetry 환경일 경우

    poetry add django-cors-headers

    나는 poetry 환경을 사용하고 있기 때문에 아래 코드를 입력했다.

     

    2. config/settings.py 파일 서드파티 리스트에 "corsheaders"를 추가해준다.

    THIRD_PARTY_APPS = [
        "rest_framework",
        "rest_framework.authtoken",
        "corsheaders", # cors-header 추가
    ]

     

    3. 같은 파일 미들웨어 리스트에 아래와 같이 추가해준다.

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'corsheaders.middleware.CorsMiddleware', # cors-header 추가
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]

     

    4. 같은 파일 내에 아래 코드 작성

    CORS_ALLOWED_ORIGINS = ["http://localhost:3000"]

    이제 localhost:3000 에서는 장고 서버를 fetch할 수 있게 된다. 

     

     

     


     

    데이터 fetch해오기

     

    타입스크립트로 작성하고 있기 때문에 일단 받아올 데이터의 타입 인터페이스를 작성해준다.

    interface IRoom {
      pk: number;
      name: string;
      country: string;
      city: string;
      price: number;
      rating: number;
      is_owner: boolean;
      photos: IPhoto[];
    }

     

    데이터의 로딩 상태를 알려주는 useState를 작성하되 기본값은 true로 설정한다.

      const [isLoading, setIsLoading] = useState(true);
      const [rooms, setRooms] = useState<IRoom[]>([]);

     

    fetchRooms() 라는 함수를 만들고 데이터를 fetch해온다.

    const fetchRooms = async () => {
        const response = await fetch("http://127.0.0.1:8000/api/v1/rooms");
        const json = await response.json();
        setRooms(json);
        setIsLoading(false);
    };

    useState rooms에 받아온 데이터값을 json화한 상태로 넣어주고, 데이터를 다 받아온 상태이기 때문에 로딩 상태는 false로 변경한다.

     

     

    fetchRooms() 함수를 useEffect로 호출시킨다.

    useEffect(() => {
        fetchRooms();
    }, []);

    fetchRooms() 가 실행되고 fetch가 시작된다.

    백엔드에서 fetch가 시작되고 response로부터 json을 추출해서 rooms 변수에 저장하고 setLoading은 false로 변경한다.

     

     

    rooms는 array로 되어있기 때문에 rooms에 map을 해서 표시한다.

    {rooms.map((room) => (
        <Room
          // imageUrl={room.photos[0].file}
          imageUrl={
            room.photos[0]?.file ??
            `https://source.unsplash.com/random/450x$`
            }
          name={room.name}
          rating={room.rating}
          city={room.city}
          country={room.country}
          price={room.price}
        />
      ))}

     

     


    전체코드

     

    📁 src/routes/Home.tsx

    import { FaStar, FaRegHeart  } from "react-icons/fa";
    import { Box, Grid, HStack, Skeleton, SkeletonText } from "@chakra-ui/react";
    import { useEffect, useState } from "react";
    import Room from "../components/Room";
    import RoomSkeleton from "../components/RoomSkeleton";
    
    interface IPhoto {
      pk: string;
      file: string;
      description: string;
    }
    
    interface IRoom {
      pk: number;
      name: string;
      country: string;
      city: string;
      price: number;
      rating: number;
      is_owner: boolean;
      photos: IPhoto[];
    }
    
    export default function Home() {
      const [isLoading, setIsLoading] = useState(true);
      const [rooms, setRooms] = useState<IRoom[]>([]);
      const fetchRooms = async () => {
        const response = await fetch("http://127.0.0.1:8000/api/v1/rooms");
        const json = await response.json();
        setRooms(json);
        setIsLoading(false);
      };
      useEffect(() => {
        fetchRooms();
      }, []);
      return (
        <Grid
          mt={10}
          px={{
            base: 10, // 모바일 버전
            lg: 40, // 큰 화면 버전
          }}
          columnGap={4}
          rowGap={8}
          templateColumns={{ // 화면 크기별 레이아웃 형태 (반응형으로 만들기)
            sm: "1fr",
            md: "1fr 1fr",
            lg: "repeat(3, 1fr)",
            xl: "repeat(4, 1fr)",
            "2xl": "repeat(5, 1fr)",
          }}
        >
         {isLoading ? (
            <>
              <RoomSkeleton />
              <RoomSkeleton />
              <RoomSkeleton />
              <RoomSkeleton />
              <RoomSkeleton />
              <RoomSkeleton />
              <RoomSkeleton />
              <RoomSkeleton />
              <RoomSkeleton />
              <RoomSkeleton />
            </>
          ) : null}
          {rooms.map((room) => (
            <Room
              // imageUrl={room.photos[0].file}
              imageUrl={
                room.photos[0]?.file ??
                `https://source.unsplash.com/random/450x$`
                }
              name={room.name}
              rating={room.rating}
              city={room.city}
              country={room.country}
              price={room.price}
            />
          ))}
        </Grid>
      );
    }

     

    하지만 계속 이런 식으로 통신하기에는 반복적인 부분이 많고 fetch해오는 api 등 데이터가 많아지면 이 방법은 비효율적일 수 있다.

    그래서 앞으로 사용할 것이 React Query이다.

     

    LIST
Designed by Tistory.