Django × Reactでハイブリッド株式管理アプリを構築する【ホーム画面編】

今回は登録した株式の一覧を表示するホーム画面を作成していきます。
項目欄の表示まで進めていきます。

イメージは下図のような感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517045/8fdbffd5-8740-0314-f70e-b7b2a030278e.png)

# URLパターン設定
ホーム画面を表示するためのURLパターンを設定します。
```py:config/urls.py
from django.contrib import admin
from django.urls import path
from django.urls.conf import include

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

```py:equity_hub/urls.py
from django.contrib import admin
from django.urls import path
from . import views

urlpatterns = [
    path('home/', views.react_view, name='home'),
    path('home/api/register/', views.EquityHubRegisterViewAPI.as_view(), name='register'),
    path('home/api/update/', views.EquityHubUpdateViewAPI.as_view(), name='update'),
    path('home/api/delete/<int:pk>/', views.EquityHubDeleteViewAPI.as_view(), name='delete'),
]
```
equtiy_hub/urls.py では ホーム画面の表示は home/ を使用します。


# ホーム画面の表示
一旦、株式情報なしでホーム画面を表示させるので Django 側の作成を行います。
```py:equity_hub/views.py
@login_required(login_url='login')
def react_view(request):
    return render(request, 'react-base.html')
```
base.html は各自 templatesフォルダを作成後、直下に作成しておいてください。
```html:templates/react-base.html
{% extends 'base.html' %}
{% block title %}{% endblock%}
{% load static %}

{% block content %}
    <div id="root"></div>
    <script type="text/javascript" src="{% static 'js/bundle.js' %}"></script>
{% endblock %}
```
js/bundle.js の箇所に React で build したファイルが読み込まれて表示されます。

合わせて作成したtemplateフォルダを登録しておきます。
```py:config/settings.py
TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [BASE_DIR / "templates"],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
            ],
        },
    },
]
```

続いて React 側の作成を行います。
```tsx:react-frontend/App.tsx
import React from 'react';
import './App.css';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import Home from './pages/home/Home';

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/home" element={<Home />} />
      </Routes>
    </Router>
  );
}

export default App;
```
URLが / と home の場合に Home.tsx が表示されるようにしておきます。

```tsx:react-frontend/index.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';

const rootElement = document.getElementById('root');

if (rootElement) {
  const root = ReactDOM.createRoot(rootElement);
  root.render(
    <React.StrictMode>
      <App />
    </React.StrictMode>
  );
} else {
  console.error('Root element not found');
}
```

src直下にpages/home/ フォルダを作成しておきます。
```tsx:src/pages/home/Home.tsx
import React, { useEffect, useState } from 'react';

const StockHoldings = () => {
  return (
    <div className="container-fluid h-100 mt-3">
      <div className="m-3 col-12">
        <ul className="list-group list-group-horizontal">
          <li className="list-group-item col active" style={{ flex: '2' }} aria-current="true">銘柄名(コード)</li>
          <li className="list-group-item col active" style={{ flex: '1' }}  aria-current="true">現在価値(円)</li>
          <li className="list-group-item col active" style={{ flex: '1' }}  aria-current="true">配当予想(%)</li>
          <li className="list-group-item col active" style={{ flex: '1' }}  aria-current="true">現在持株数</li>
          <li className="list-group-item col active" style={{ flex: '1' }}  aria-current="true">配当予想額(円)</li>
          <li className="list-group-item col active" style={{ flex: '1' }}  aria-current="true">配当額/全体配当額</li>
          <li className="list-group-item col active" style={{ flex: '1' }}  aria-current="true">購入数</li>
          <li className="list-group-item col active" style={{ flex: '1' }}  aria-current="true">購入後配当額</li>
          <li className="list-group-item col active" style={{ flex: '1' }}  aria-current="true">購入後配当額/全体配当額
          </li>
        </ul>
      </div>
    </div>
  );
};

export default StockHoldings;
```

# React で build実行
```sh
cd react-frontend

npx webpack
```
上記のコマンドを実行すると webpack.config.js で設定したディレクトリにファイルが作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517045/f9ef10bf-8eb2-dcf4-1bea-cbadefb2d333.png)

この bundle.js が Django側で作成した react-base.html で読み込まれます。

# 確認
Djangoプロジェクト直下に移動して起動してみます。
```sh
cd ../

python manage.py runserver
```
http://127.0.0.1:8000/home/ にアクセスして下記のように項目が表示されれば問題ありません。
※CSSやBootstrapなど使っているのでデザインが違っても問題ありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517045/8fdbffd5-8740-0314-f70e-b7b2a030278e.png)

# 最後に
次回は登録している株式情報の取得処理を作成します。
ホーム画面の構成は、デザインになるので省略して機能のみの説明になると思います。