Django REST framework(DRF) と React でTodoアプリ(SPA)を作る②

前回の記事に続いてReactでフロントエンドの実装を行います。

準備

前回に続いて今回はフロント側の実装をしていきます。前回作ったdrf-react-todoでreactアプリを作成します。

npx create-react-app todo_front
cd todo_front
yarn start

これでブラウザが立ち上がり、スタートページが閲覧できたらreactの準備は完了です。

フロントエンド実装

Todo一覧表示(GET)

フロントエンドの実装をしていきます。srcフォルダ内にcomponentsフォルダを作成し、その中に更にDrfApi.jsファイルを作成します。まずは先ほどのAPIへGETでリクエストしてTodoを一覧表示してみます。DrfApi.jsを以下のようにしてください。

import React, {useState, useEffect} from 'react'

const DrfApi = () => {

    const [todos, setTodos] = useState([])

    useEffect(() => {
        try {
            async function fetchTodoAPI(){
                const res = await fetch("http://localhost:8000/api/todos/")
                const todoJson = await res.json()
                setTodos(todoJson)
            }
            fetchTodoAPI()
        } catch (e) {
            console.error(e)
        }
    }, [])

    return (
        <div>
            <ul>
                {
                    todos.map(todo => 
                    <li key={todo.id}>{todo.title}: {todo.content}</li>
                    )
                }
            </ul>
        </div>
    )
}

export default DrfApi

ここではuseStateとuseEffectを使用して一覧表示しています。

useEffectの第二引数に空の配列を渡すことでマウント時に第一引数の関数が実行されます。今回useEffectの第一引数では、Django REST framework で作ったAPIにGETリクエストを投げて返ってきた値をtodosにセットしています。

次にreturn内でmapを使ってtodoの中から値を1つずつ取り出して表示しています。

次にApp.jsでDrfApiを呼び出します。

import React from 'react';
import './App.css';
import DrfApi from './components/DrfApi'; // 追加

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <DrfApi /> // 追加
      </header>
    </div>
  );
}

export default App;

一度動作確認をしてみます。ターミナルのウィンドウを2つ用意して1つ目でDjangoのrunserver、2つ目のターミナルでreactを立ち上げます。まずは1つ目のターミナル(drf-react-todo)。

pipenv shell
cd todo_API
./manage.py runserver

次に別のウィンドウで以下のコマンドを実行

cd todo_front
yarn start

正しく動作するとブラウザが起動して追加したTodoが一覧で表示されます。

新規Todo作成(POST)

次にTodoの新規作成を行えるようにしていきます。先ほどと同じくDrfAPI.jsに変更を加えていきます。まず先ほどのuseStateのしたにもう1つ別のStateを作成します。

const [todos, setTodos] = useState([])
const [editTodo, setEditTodo] = useState({id:'', title:'', content:''}) //追加

次にreturnの中に変更を加えてフォームを作ります。先ほどの<ul>の上に追記します。

<div className='container'>
                <input className='form-control' type='text' name='title' placeholder='title' value={editTodo.title} onChange={handleInputChange()} required />
                <br />
                <textarea className='form-control' name='content' placeholder='content' value={editTodo.content} onChange={handleInputChange()} required />
                <br /><br />
</div>

これでフォームに変更があるたびにhandleInputChangeが呼ばれます。次にこのhandleInputChange関数を作っていきます。returnのすぐ上あたりに作っておきます。

const handleInputChange = () => e => {
        const value=e.target.value;
        const name = e.target.name
        setEditTodo({...editTodo, [name]: value})
}

この関数では変更のあったフォームの値をeditTodoに格納していきます。

ボタンをtextareaの下に追加します。このボタンが押されるとcreateNewTodoが実行されます。createNewTodoには引数としてeditTodoが渡されます(つまり現在フォームに入力されている値)。

<button onClick={()=>createNewTodo(editTodo)} className='btn btn-primary'>Create</button>

メインのcreateNewTodoを作っていきます。

    const createNewTodo = (todo) => {
        try {
            async function fetchCreateTodo(todo){
                const config = {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify(todo)
                }
                const res = await fetch(`http://localhost:8000/api/todos/`, config)
                const todoJson = await res.json()
                setTodos([todoJson, ...todos])
                setEditTodo({id:'', title:'', content:''})
            }
            fetchCreateTodo(todo)
        } catch(e){
            console.error(e)
        }
    }

async/awaitでDRFのAPIに引数で受け取ったtodoを渡します。configでメソッドの指定やheaderの設定、todoをJSON形式に変更します。返ってきた値をtodosに追加します。加えて送信した値がフォームに残ってしまうのでeditTodoを空にしておきます。

ブラウザで動作確認をすると実際に新しくTodoの作成が可能になっているはずです。

今回はここまで、次回はTodoの編集と削除機能を追加してみようと思います。

コメント

タイトルとURLをコピーしました