React 入門
JavaScript コメント掲示板アプリの開発
ボタンクリックを処理して表示内容を更新する
前のページで設置した「次のページ」ボタンをクリックしたことを検知し表示内容を更新するコードを作成します.同時にボタンのラベルにはリンク先のURLも一時的に表示しておきます.まず,ボタンに onClick
属性を追加し,実行したい関数名 handleCurrentPageNext
を { ... }
で囲って与えます.
src/components/CommentListPage.js(抜粋)
<div className="commentsHeader">
<div>コメント総数:{results.count}</div>
<div>
<button>前のページ ({results.previous})</button>
<button
onClick={handleNextPageButton}
>次のページ ({results.next})</button>
</div>
</div>
次に,上で指定した関数 handleNextPageButton
を定義します.定義する場所は CommentListPage()
関数内で,return
文よりも前です.
src/components/CommentListPage.js(抜粋)
const handleNextPageButton = () => {
console.log("handleNextPageButton :", results.next);
};
これでクリックされたことと,次にリクエストすべき API の URL が取得できました.
実際に API にリクエストして表示内容を更新します.
src/components/CommentListPage.js(抜粋)
const handleNextPageButton = () => {
// console.log("handleNextPageButton :", results.next);
axios.get(results.next)
.then(res => setResults(res.data))
.catch(err => console.log(err.message));
};
ページを進めると「前のページ」と「次のページ」の URL が取得できていることもわかります.
しかし,このままでは最後のページまで進んだ後に「次のページ」ボタンをクリックすると,リクエストの URL が null 値であるために処理に失敗します.同時にコンソールには「Cannot read properties of null (reading 'protocol')」と表示されます.
したがって,リクエスト送信前に URL が null であるかどうかをチェックしておくとよいでしょう.
src/components/CommentListPage.js(抜粋)
const handleNextPageButton = () => {
if (results.next === null) {
return;
}
axios.get(results.next)
.then(res => setResults(res.data))
.catch(err => console.log(err.message));
};
ここで一旦コード全体を確認します.
src/components/CommentListPage.js
import React from 'react'
import { useState, useEffect } from 'react';
import axios from 'axios';
import Comment from './Comment';
import CreateForm from './CreateForm';
const CommentListPage = () => {
const [results, setResults] = useState({
"count":10,
"next":"http://127.0.0.1:8000/comments/?page=2",
"previous":null,
"results":[
{
"id":9999,
"title":"ダミー",
"body":"ダミーの本文",
"updated_at":"2023-11-21T11:20:00"
},
{
"id":10000,
"title":"ダミーのタイトル",
"body":"ダミーです",
"updated_at":"2023-11-21T11:10:00"
}
]
});
useEffect(() => {
const url = "http://127.0.0.1:8000/comments/";
axios.get(url)
.then(res => setResults(res.data))
.catch(err => console.log(err.message));
}, []);
const handleDeleteButtonClick = (commentId) => {
if (!window.confirm("削除しますか?")) {
return;
}
const newComments = [...results.results].filter((comment) => {
return comment.id !== commentId;
});
const newResults = {
"count": results.count - 1, // コメント数は1減らす
"previous": results.previous,
"next" : results.next,
"results": newComments
};
setResults(newResults);
};
const commentItems = results.results.map((comment) => {
return (
<Comment
key={comment.id}
comment={comment}
onDelete={handleDeleteButtonClick}
/>
)
});
const handelCreateFormSubmit = (title, body) => {
const newComments = [...results.results]; // スプレッド構文でコメントの配列だけを取り出す
newComments.unshift({ // unshift で先頭に追加,push では最後に追加
id: Date.now(),
title: title,
body: body,
updated_at: "2024-02-25T15:30:00",
});
const newResults = {
"count": results.count + 1, // コメント数は1増やす
"previous": results.previous,
"next" : results.next,
"results": newComments, // これがコメントの配列
};
setResults(newResults); // 画面を更新
}
const handleNextPageButton = () => {
if (results.next === null) {
return;
}
axios.get(results.next)
.then(res => setResults(res.data))
.catch(err => console.log(err.message));
};
return (
<div className="container">
<h1>コメント一覧</h1>
<div className="commentsHeader">
<div>コメント総数:{results.count}</div>
<div>
<button>前のページ ({results.previous})</button>
<button
onClick={handleNextPageButton}
>次のページ ({results.next})</button>
</div>
</div>
{commentItems}
<CreateForm
onSubmit={handelCreateFormSubmit}
/>
</div>
)
}
export default CommentListPage
「次のページ」ボタンの動作ができたので「前のページ」ボタンの処理もほぼ同じ方法でコーディングします.
src/components/CommentListPage.js
import React from 'react'
import { useState, useEffect } from 'react';
import axios from 'axios';
import Comment from './Comment';
import CreateForm from './CreateForm';
const CommentListPage = () => {
const [results, setResults] = useState({
"count":10,
"next":"http://127.0.0.1:8000/comments/?page=2",
"previous":null,
"results":[
{
"id":9999,
"title":"ダミー",
"body":"ダミーの本文",
"updated_at":"2023-11-21T11:20:00"
},
{
"id":10000,
"title":"ダミーのタイトル",
"body":"ダミーです",
"updated_at":"2023-11-21T11:10:00"
}
]
});
useEffect(() => {
const url = "http://127.0.0.1:8000/comments/";
axios.get(url)
.then(res => setResults(res.data))
.catch(err => console.log(err.message));
}, []);
const handleDeleteButtonClick = (commentId) => {
if (!window.confirm("削除しますか?")) {
return;
}
const newComments = [...results.results].filter((comment) => {
return comment.id !== commentId;
});
const newResults = {
"count": results.count - 1, // コメント数は1減らす
"previous": results.previous,
"next" : results.next,
"results": newComments
};
setResults(newResults);
};
const commentItems = results.results.map((comment) => {
return (
<Comment
key={comment.id}
comment={comment}
onDelete={handleDeleteButtonClick}
/>
)
});
const handelCreateFormSubmit = (title, body) => {
const newComments = [...results.results]; // スプレッド構文でコメントの配列だけを取り出す
newComments.unshift({ // unshift で先頭に追加,push では最後に追加
id: Date.now(),
title: title,
body: body,
updated_at: "2024-02-25T15:30:00",
});
const newResults = {
"count": results.count + 1, // コメント数は1増やす
"previous": results.previous,
"next" : results.next,
"results": newComments, // これがコメントの配列
};
setResults(newResults); // 画面を更新
}
const handlePrevPageButton = () => {
if (results.previous === null) {
return;
}
axios.get(results.previous)
.then(res => setResults(res.data))
.catch(err => console.log(err.message));
};
const handleNextPageButton = () => {
if (results.next === null) {
return;
}
axios.get(results.next)
.then(res => setResults(res.data))
.catch(err => console.log(err.message));
};
return (
<div className="container">
<h1>コメント一覧</h1>
<div className="commentsHeader">
<div>コメント総数:{results.count}</div>
<div>
<button
onClick={handlePrevPageButton}
>前のページ ({results.previous})</button>
<button
onClick={handleNextPageButton}
>次のページ ({results.next})</button>
</div>
</div>
{commentItems}
<CreateForm
onSubmit={handelCreateFormSubmit}
/>
</div>
)
}
export default CommentListPage