# Разработка приложений на React + Django


<!--more-->

# Разработка приложений на React + Django

Простая настройка окружения разработчика для создания приложений с использованием React и Django 
через проксирование запросов, без настройки CORS.

Современный пользовательский интерфейс в веб-приложениях часто делают на таких фреймворках, как React. Серверная же
часть может использовать различные технологии. В данной статье рассмотрим наиболее простой способ подружить React и
Django.


## Установка Django

Создаем папку для будущего приложения и переходим в нее. Далее создаем виртуальное окружение и устанавливаем необходимые
пакеты.

```shell
python3 -m venv venv
source venv/bin/activate    # для Linux/Mac
venv\Scripts\activate    # для Windows
pip install django django-rest-framework
```

Создаем новый проект Django, например, назовем **backend**

```shell
django-admin startproject backend
cd backend
```

и новое приложение, которое назовем, например, **myapi**

```shell
python manage.py startapp myapi
python manage.py migrate
python manage.py createsuperuser --username $USER --email admin@example.com
```

Сохраняем установленные библиотеки в файл `requirements.txt` и поддерживаем его в актуальном состоянии. В дальнейшем, 
он нам понадобится для развертывания приложения на компьютере другого разработчика или продакшн сервере.

```shell
pip freeze > requirements.txt
```

Теперь можно запустить ваше приложение

```shell
python manage.py runserver
```

На этом этапе у вас уже должна работать админка [http://127.0.0.1:8000/admin/](http://127.0.0.1:8000/admin/)


### Добавляем простой API обработчик

Добавим в файл настроек `backend/settings.py` наши модули

```python
INSTALLED_APPS = [
    ...
    'rest_framework',
    'myapi',
]
```

Так же, начиная с Django 4.0, мы должны указать список доверенных источников для небезопасных запросов (например, POST).
Еще зададим значения STATIC_ROOT и STATIC_URL, они понадобятся на этапе развертывания проекта.

```python
CSRF_TRUSTED_ORIGINS = ['http://localhost:3000', 'http://127.0.0.1:3000']
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
```

Создаем простой обработчик, для этого напишем его в файле `myapi/views.py`. Обработчик можно писать на классах или в
виде отдельных функций. Рассмотрим оба варианта.

```python
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import generics

@api_view(['GET'])
def Hello(request):
    if request.method == 'GET':
        data = {'message': 'Hello world!'}
        return Response(data)

class Bye(generics.RetrieveAPIView):
    def get(self, request, *args, **kwargs):
        data = {'message': 'Bye world!'}
        return Response(data)
```

Далее нужно настроить маршрутизацию адресов. Для этого создаем в нашем модуле файл маршрутизации `myapi/urls.py`
и прописываем в него все вызовы API функций.

```python
from django.urls import path
from myapi import views

urlpatterns = [
    path('hello/', views.Hello),
    path('bye/', views.Bye.as_view()),
]
```

Далее открываем основной файл маршрутизации приложения `backend/urls.py` и добавляем в него пути к нашим модулям

```python
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('myapi.urls')),
    # Можно подключать несколько модулей с непересекающимися подпутями на один путь
    # path('api/', include('another.urls')),
]
```

Если все написали правильно, то теперь можно посмотреть как работают наши API
запросы [http://127.0.0.1:8000/api/hello/](http://127.0.0.1:8000/api/hello/)
и [http://127.0.0.1:8000/api/bye/](http://127.0.0.1:8000/api/bye/).

## Установка React
Далее нужно выбрать вариант установки: Стандартный или с Vite

### Стандартная установка React

Устанавливаем React. Для этого переходим в корневой
каталог нашего проекта и запускаем установку. Для примера будем использовать TypeScript.

```shell
cd ..
npx create-react-app frontend --template typescript
```

Поскольку Django сервер и React сервер -- это два разных сервера, которые друг про друга ничего не знают, будем проксировать
все запросы к API из React сервера в Django. Это проще и удобнее, чем настраивать кросс-доменные
запросы [CORS](https://developer.mozilla.org/ru/docs/Web/HTTP/CORS). Редактируем файл `frontend/package.json` и
добавляем туда строку, указывающую использование прокси.

```json
{
    "proxy": "http://localhost:8000",
  ...
}
```

Теперь все внешние запросы будут перенаправляться через этот прокси в наше Django приложение. Это удобно тем, что данная
настройка влияет только на сервер разработки и никак не влияет на конечное приложение, развернутое в продакшене.
Так же, на стороне Django сервера не нужно вносить никаких изменений. Подробнее можно почитать в
официальной [документации](https://create-react-app.dev/docs/proxying-api-requests-in-development/).

Переходим в каталог **frontend** и запускаем сервер разработки

```shell
cd frontend
npm start
```

Сервер должен успешно запуститься и откроется страница приложения [http://localhost:3000/](http://localhost:3000/)

### Установка React с Vite

Если мы хотим использовать более современную систему разработки и сборки проекта, можем установить React с системой Vite.
Также будем использовать TypeScript. Для установки обычного JavaScript используйте шаблон `react`.

```shell
cd ..
npm create vite@latest frontend -- --template react-ts
```

Настроим Vite для отправки запросов к нашему API через Proxy. Редактируем `frontend/vite.config.ts`

```ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
    plugins: [react()],
    server: {
        port: 3000,
        proxy: {
            '/api': {
                target: 'http://127.0.0.1:8000',
                changeOrigin: true,
                secure: false,
                ws: true,
            }
        },
    },
})
```

Запустим среду разработки

```shell
cd frontend
npm install
npm run dev
```

## Установка Tailwind CSS

Для создания красивого, современного пользовательского интерфейса будем использовать Tailwind CSS. Установим его.

```shell
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
```

И настроим, поправив файл `tailwind.config.js`
```js
/** @type {import('tailwindcss').Config} */
export default {
    content: [
        "./index.html",
        "./src/**/*.{js,ts,jsx,tsx}",
    ],
    theme: {
        extend: {},
    },
    plugins: [],
}
```

Далее подключим к нашим стилям `src/index.css` библиотеку Tailwind CSS. Для этого очищаем все содержимое этого файла,
оставшееся от шаблонного примера, и записываем следующее:

```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

## Простое приложение для тестирования API

Сделаем простенький API запрос. Открываем `src/App.tsx` и заменяем старое содержимое на это:

```typescript jsx
import { useState } from 'react';

function App() {
    const [url, setUrl] = useState('hello');
    const [message, setMessage] = useState('Wait...');
    const handleClick = () => {
        fetch('/api/'+url)
            .then(response => response.json())
            .then(json => {
                setMessage(json['message']);
                if(url==='hello')
                    setUrl('bye');
                else
                    setUrl('hello');
            })
            .catch(error => console.error(error));
    };

    return (
        <div  className="mx-auto max-w-3xl px-4 sm:px-6 xl:max-w-5xl xl:px-0">
            <button
                className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 mt-4 rounded"
                onClick={handleClick}>
                <pre>{message}</pre></button>
        </div>
    );
}
export default App;
```

Если у вас при нажатии на кнопку надпись не меняется, убедитесь, что Django сервер тоже запущен в другом окне.

В итоге мы получили простое приложение с интерфейсом на React + Tailwind CSS, состоящее из одной кнопки и обработчиком 
API запросов на Django.

В следующей статье мы настроим продакшн сервер с нашим приложением в Docker контейнерах и SSL сертификатом
[Развертывание React + Django]({{< relref "deploy-react-and-django" >}}) для публичного доступа.

