神戸学院大学 経営学部 林坂ゼミ

React 入門トップページ

« 戻る 次へ »

React 入門

JavaScript コメント掲示板アプリの開発

コメント削除機能の実装

コメントの投稿機能が実現できたので,次は削除機能を実装してきます.

まず,コメント一つひとつに対して削除するためのボタンを配置したいので,Comment コンポーネントを次の通り編集します.このとき,deleteButton という名前のクラスを設定しておきます.

src/components/Comment.jsimport React from 'react'

const Comment = (props) => {
  return (
    <article>
      <div className="title">
        {props.comment.title}
      </div>
      <div className="body">
        {props.comment.body}
      </div>
      <div className="deleteButton">
        <button>
          削除
        </button>
      </div>
    </article>
  )
}

export default Comment

削除ボタンは画面の右側に配置したいので,index.css にスタイルを追加します.

src/index.css(抜粋).deleteButton {
  text-align: right;
}

画面の右側に削除ボタンが配置されました.ブラウザの横幅を変化させて配置を確認してください.

react-2024-41

次に,削除ボタンがクリックされたことを検知できるようにします.そのために,button要素に onClick 属性を追加し,クリック時に実行される関数名 (handleClickDeleteButton) を指定します.

src/components/Comment.js(抜粋)<div className="deleteButton">
  <button
    onClick={handleClickDeleteButton}
  >
    削除
  </button>
</div>

同じ名前の関数 (handleClickDeleteButton) を定義します.この関数ではとりあえずボタンがクリックされたことをコンソールにログとして出力する処理だけを入力しておきます.

src/components/Comment.js(抜粋)const handleClickDeleteButton = () => {
  console.log("handleClickDeleteButton");
};

コメントの削除ボタンをクリックしたことを検知できるようになりました.しかし,どのコメントのボタンを押したかが現時点では取得できていません.

Comment コンポーネントには props の中にコメントの情報があり,その中には id の情報も含まれています.次の方法でコメントの ID を取得できました.

src/components/Comment.js(抜粋)const handleClickDeleteButton = () => {
  console.log("handleClickDeleteButton", props.comment.id);
};
react-2024-42

上では Comment コンポーネントでコメントの ID を取得しています.実際に削除の処理は CommentListPage コンポーネントで行う必要があるので,CommentListPage コンポーネントに handleDeleteButtonClick 関数を定義します.

src/components/CommentListPage.js(抜粋)const handleDeleteButtonClick = () => {
  console.log('handleDeleteButtonClick');
};

そして,Comment コンポーネントに onDelete という名前で関数を渡します.なお,上の handleDeleteButtonClick 関数の定義は次の commentItems の定義よりも上に入力しなければならないことに注意してください.

src/components/CommentListPage.js(抜粋)const commentItems = results.results.map((comment) => {
  return (
    <Comment
      key={comment.id}
      comment={comment}
      onDelete={handleDeleteButtonClick}
    />
  )
});

Comment コンポーネントには propsonDelete 関数が渡されたので,これを handleClickDeleteButton 関数内で実行します.

src/components/Comment.js(抜粋)const handleClickDeleteButton = () => {
  // console.log("handleClickDeleteButton", props.comment.id);
  props.onDelete();
};

どのコメントに対する削除ボタンがクリックされたのかを知りたいので,Comment コンポーネントでの onDelete の呼び出し時にコメントの ID を渡します.

src/components/Comment.js(抜粋)const handleClickDeleteButton = () => {
  // console.log("handleClickDeleteButton", props.comment.id);
  props.onDelete(props.comment.id);
};

CommentListPage コンポーネントでは Comment コンポーネントから渡されたコメントの ID を受け取ります.

src/components/CommentListPage.js(抜粋)const handleDeleteButtonClick = (commentId) => {
  console.log('handleDeleteButtonClick', commentId);
};
react-2024-43

ここまでの作業の結果,どのコメントに対する削除ボタンがクリックされたかを CommentListPage コンポーネントで検知できるようになりました.続いて,実際に削除を行うための処理をコーディングします.

src/components/CommentListPage.js(抜粋)const handleDeleteButtonClick = (commentId) => {
  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);
};

上のコードの詳細について説明します.2行目の [...results.results] はスプレッド構文です.コメントの一覧を配列に展開しています.filter ではコメントの配列を一つずつ順番に取り出して comment に代入し,削除対象の commentID と等しくないものを配列にして返して newComments オブジェクト定数を作成しています.その結果として削除対象のコメントだけが削除されたことになります.その後,5行目で newResults オブジェクトを生成するときに,対象コメントが削除された残りのコメント配列オブジェクト newComments を指定しています.最後に11行目の setResults()results を更新した結果,画面の表示が更新されることになります.

新規にコメントを投稿した後に,ブラウザで実際に削除ボタンを押してコメントが削除できることを確認します.

react-2024-44

削除ボタンを押したときは確認画面を表示してもよいでしょう.

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);
};

ブラウザで動作を確認します.確認画面で「OK」を押したときにだけコメントが削除できるようになりました.

react-2024-45

ここでも少々複雑な処理になりました.現時点での CommentListPage.js 全体を示しておきます.

src/components/CommentListPage.jsimport React from 'react'
import { useState } from 'react';
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":9,
        "title":"9個目のコメント",
        "body":"コメントの本文9",
        "updated_at":"2023-11-21T11:20:00"
      },
      {
        "id":10,
        "title":"10個目のコメント",
        "body":"コメントの本文10",
        "updated_at":"2023-11-21T11:10:00"
      }
    ]
  });

  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); // 画面を更新
  }

  return (
    <div className="container">
      <h1>コメント一覧</h1>
      {commentItems}

      <CreateForm
        onSubmit={handelCreateFormSubmit}
      />
    </div>
  )
}

export default CommentListPage

Comment.js の全体も示しておきます.

src/components/Comment.jsimport React from 'react'

const Comment = (props) => {

  const handleClickDeleteButton = () => {
    props.onDelete(props.comment.id);
  };

  return (
    <article>
      <div className="title">
        {props.comment.title}
      </div>
      <div className="body">
        {props.comment.body}
      </div>
      <div className="deleteButton">
        <button
          onClick={handleClickDeleteButton}
        >
          削除
        </button>
      </div>
    </article>
  )
}

export default Comment

目次に戻る