react×django(django-rest-framework)の環境構築

# この記事の概要

React×Django(django-rest-framework)の環境構築について記載する。

# React×Djangoの環境構築前の作業

## Reactの環境構築

https://qiita.com/enyantaro/items/0bcd73839599b4132109

## Djangoの環境構築

https://qiita.com/enyantaro/items/9d06112be644a3caac13

## django-rest-frameworkのインストールや設定方法

https://qiita.com/enyantaro/items/4110b9f58ac4a3e0f1ae

# React×Djangoの環境構築

```
// Django環境作成(バックエンド)
$ mkdir backend
$ cd backend
$ django-admin startproject config .
$ python3 manage.py startapp app
$ python3 manage.py migrate
$ python3 manage.py runserver

// react環境作成(フロントエンド)
$ mkdir frontend
$ cd frontend
$ npx create-react-app .
$ npm install axios # axioxのインストール
```

# React×Djangoの設定・アプリ作成

## Djangoの作成(バックエンド)

### configの設定

```config/settings.py
INSTALLED_APPS = [
    'rest_framework', #　追加
    'corsheaders', #　追加
    'api', #追加
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware', #　追加
    'django.middleware.common.CommonMiddleware', #　追加
]

REST_FRAMEWORK = { #　追加
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny',
    ]
}

CORS_ORIGIN_WHITELIST = ( #　追加
    'http://localhost:3000',
)
```

```config/urls.py
from django.contrib import admin
from django.urls import path, include # 追加

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api-auth/', include('rest_framework.urls')), # 追加
    path('api/', include('api.urls')), # 追加
]
```

### modelsの作成

```api/models.py
from django.db import models
from django.utils import timezone # timezoneのインポート

class Food(models.Model):
    name = models.CharField(verbose_name='食材名', max_length=40)
    content = models.TextField(verbose_name='食材説明', max_length=400, blank=True, null=True)
    created_at = models.DateTimeField(verbose_name='作成日時', default=timezone.now)
    updated_at = models.DateTimeField(verbose_name='編集日時', blank=True, null=True)
    def __str__(self):
        return self.name
```

### serializersの作成

```api/serializers.py
from rest_framework import serializers
from .models import Food

class FoodSerializer(serializers.ModelSerializer):
    created_at = serializers.DateTimeField(format="%Y-%m-%d %H:%M", read_only=True)
    updated_at = serializers.DateTimeField(format="%Y-%m-%d %H:%M", read_only=True)

    class Meta:
        model = Food
        fields = '__all__'
```

### viewsの作成※ビューセットを使う

```api/views.py
from rest_framework import viewsets
from .models import Food
from .serializers import FoodSerializer

class FoodViewSet(viewsets.ModelViewSet):
    queryset = Food.objects.all()
    serializer_class = FoodSerializer
```

#### urlsの作成

```api/urls.py
from django.urls import path, include
from rest_framework import routers
from .views import FoodViewSet

foodRouter = routers.DefaultRouter()
foodRouter.register('food', FoodViewSet)

urlpatterns = [
    path('', include(foodRouter.urls)),
]
```

## Reactの作成(フロントエンド)

### App.jsの設定

```App.js
import FoodList from "./components/FoodList";


function App() {
  return (
    <>
      <FoodList />
    </>
  );
}

export default App;
```

### FoodList.jsの設定

```FoodList.js
import { useState, useEffect } from 'react';
import axios from 'axios';

const FoodList = () => {
    const initState = {
        id: '',
        name: '',
        content: '',
    }

    const [list, setList] = useState(initState);
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        axios.get(`http://localhost:8000/api/food/`)
            .then((res) => {
                setList(res.data);
                setLoading(false);
            })
            .catch((err) => {
                throw new Error(err)
            })
            .finally(() => {

            })
    }, [])

    return (
        <>
            <h1>foodlist</h1>
            {
                loading?
                <h1>...Loading</h1>
                :
                <>
                    {list.map(f => <p key={f.id}>{f.name}</p>)}
                </>
                
            }
        </>
    )
}

export default FoodList;
```