ReactでDjango REST frameworkのバックエンドAPIと連携してタスク一覧を表示させる

はじめに

【フロントエンドとの連携】CORS設定でフロントエンドからAPIを呼び出せるようにするでフロントエンドとの連携に必要なCORS設定を行った。

今回はReactを使用して、DRFとの連携を行い、最終的にはタスク一覧をReactの開発環境で表示させる。

viteを使ってReactプロジェクトを作成

vite(ヴィート)は、ReactやVueのフロントエンド開発で使われる高速なビルドツール。

ビルドツールとは、プログラムの開発において、ソースコードを変換・最適化して実行可能な形式にするためのツール。

新規Reactプロジェクトを使用するので、gitでリポジトリを作成した。

ローカルにもフォルダを作成する。

リポジトリの初期化を行なった。

Mac:react_todo shibatahiroshitaka$ git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint: 
hint:   git config --global init.defaultBranch <name>
hint: 
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint: 
hint:   git branch -m <name>
Initialized empty Git repository in /Users/shibatahiroshitaka/Downloads/react/react_todo/.git/
Mac:react_todo shibatahiroshitaka$ git remote add origin https://github.com/ki-hi-ro/react_todo.git
Mac:react_todo shibatahiroshitaka$ 

現状、react_todoにいるので、以下のコマンドを使用すると、react_todoの中にreact_todoが作成されてしまう。

npm create vite@latest react_todo --template react

カレントディレクトリにインストールするには、フォルダ名の代わりに「.」を使用する。

npm create vite@latest . --template react

フレームワークとバリアント(フレームワークの設定)を選択したらreactのプロジェクトフォルダの中身がインストールされた。

Mac:react_todo shibatahiroshitaka$ npm create vite@latest . --template react
│
◇  Select a framework:
│  React
│
◇  Select a variant:
│  TypeScript + SWC
│
◇  Scaffolding project in /Users/shibatahiroshitaka/Downloads/react/react_todo...
│
└  Done. Now run:

  npm install
  npm run dev

SWC(Speedy Web Compiler)は、Rustで書かれた超高速なJS/TSのコンパイラのこと。

Rustは、C++の代替として開発され、メモリ安全性を保証しつつ、高パフォーマンスを実現できるのが特徴。

必要なパッケージをインストール

npm installで140個のパッケージをインストールした。WARNという警告が出ていたが、以下では省略した。

Mac:react_todo shibatahiroshitaka$ npm install

added 140 packages, and audited 141 packages in 11s

40 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

node_modulesはgitignoreに入っていた。量が多いためと考えられる。

Django REST frameworkとの通信には、axiosを使用するので、追加でインストールする。

Mac:react_todo shibatahiroshitaka$ npm install axios

added 23 packages, and audited 164 packages in 2s

46 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

ReactからDjango APIにアクセス

Django側のAPI(http://127.0.0.1:8000/api/tasks/)からデータを取得し、ReactのuseEffectを使って一覧を表示するコンポーネントを作成する。

useEffectとは、Reactのフック(Hook)の一つで副作用(Side Effects)を処理するための関数。

フックとは、Reactの関数コンポーネントに「状態管理」や「ライフサイクル処理」を追加するための関数。

関数コンポーネント(Functional Component)とは、ReactでUIを定義するための関数ベースのコンポーネント。

副作用とは、関数の外部に影響を与える処理のこと。関数は通常、入力(引数)に対して出力(返り値)を返すだけ。以下のようなコンソールログは、関数の外(コンソール)に影響を与えるため、副作用の一つ。

console.log('AAA');

APIからデータを取得するのは副作用なので、useEffectによって適切に制御する必要がある。

TaskList.jsを作成

src/components/TaskList.jsを作成して、APIからデータを取得して表示する。

import { useState, useEffect } from "react";
import axios from "axios";

const API_URL = "http://127.0.0.1:8000/api/tasks/";

const TaskList = () => {
  const [tasks, setTasks] = useState([]);

  useEffect(() => {
    axios.get(API_URL)
      .then(response => setTasks(response.data))
      .catch(error => console.error("Error fetching tasks:", error));
  }, []);

  return (
    <div>
      <h2>タスク一覧</h2>
      <ul>
        {tasks.map(task => (
          <li key={task.id}>{task.title}</li>
        ))}
      </ul>
    </div>
  );
};

export default TaskList;

useStateとは、Reactのフックの一つで、関数コンポーネント内で状態を管理するための関数。

以下の部分では、useStateフックで「tasks」という状態を定義している。setTasksはそれを更新するもの。useState([])では、初期値として空の配列([])を設定している。

const [tasks, setTasks] = useState([]);

この辺の解説記事は別途書いていく。

TypeScriptを選択していたので、TaskList.jsをTaskList.tsxに変更する。

拡張子と以下の太字部分を修正した。

import { useState, useEffect } from "react";
import axios from "axios";

const API_URL = "http://127.0.0.1:8000/api/tasks/";

interface Task {
  id: number;
  title: string;
}

const TaskList: React.FC = () => {
  const [tasks, setTasks] = useState<Task[]>([]);

  useEffect(() => {
    axios.get<Task[]>(API_URL)
      .then(response => setTasks(response.data))
      .catch(error => console.error("Error fetching tasks:", error));
  }, []);

  return (
    <div>
      <h2>タスク一覧</h2>
      <ul>
        {tasks.map(task => (
          <li key={task.id}>{task.title}</li>
        ))}
      </ul>
    </div>
  );
};

export default TaskList;

TaskList.jsをTaskList.tsxに変更 · ki-hi-ro/react_todo@46c1b47

App.tsxに組み込む

src/App.tsxを修正し、TaskListコンポーネントを表示する。

デフォルトのApp.tsxはこちら。

import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'

function App() {
  const [count, setCount] = useState(0)

  return (
    <>
      <div>
        <a href="https://vite.dev" target="_blank">
          <img src={viteLogo} className="logo" alt="Vite logo" />
        </a>
        <a href="https://react.dev" target="_blank">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <h1>Vite + React</h1>
      <div className="card">
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
        <p>
          Edit <code>src/App.tsx</code> and save to test HMR
        </p>
      </div>
      <p className="read-the-docs">
        Click on the Vite and React logos to learn more
      </p>
    </>
  )
}

export default App

既存の記述はほとんど削除して以下に書き換えた。

import TaskList from "./components/TaskList";

function App() {
  return (
    <div>
      <h1>タスク管理アプリ</h1>
      <TaskList/>
    </div>
  );
}

export default App

importのところでtsのエラーが出ている。

モジュール './components/TaskList' の宣言ファイルが見つかりませんでした。'/Users/hiroki/Downloads/react_todo/src/components/TaskList.js' は暗黙的に 'any' 型になります。ts(7016)

このエラーの原因は、TypeScriptがTaskList.tsxを正しく認識できていないということ。

VSCodeを開き直したら、TaskList.tsxを正しく認識してくれたのかエラーが解消されていた。

App.tsxを修正 · ki-hi-ro/react_todo@094f5a2

Reactの開発サーバーを起動

TaskList.jsが残っていたことによるエラーを解決して、npm run devで開発サーバーを起動すると上記の画面になった。

当初の想定としては、DjangoのバックエンドAPIで構築したタスクデータをReactのフロントエンドに表示させることだったので、それを目指していこう。

データを表示させる

CORS設定を見直すことで、発生していた3つのエラーが芋づる式に解決したで奮闘した結果、以下のようにDjangoのバックエンドで作成したデータをAPIで取得して、フロントエンドのReactで表示させることができた。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です