0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[React][L6] リストの項目をボタンで削除・出力する2

Posted at

実施条件

[React][L5] リストの項目をボタンで削除・出力するを理解していること

環境

MacBook Pro (2.3 GHz 8コアIntel Core i9)
macOS 14.0(23A344)
Homebrew 4.3.8
gh 2.52.0

ソースコードの前に

フォルダ構成

folda_structure
├── package.json
├── public/
│   └── index.html
├── src/
│   ├── index.jsx
│   ├── Todo.jsx
│   └── styles.css
│  

index.html

index.html
<!DOCTYPE html>
<html lang="en">
  <head> </head>

  <body>
    <div id="root"></div>
  </body>
</html>

index.jsx

index.jsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";

import { Todo } from "./Todo";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(
  <StrictMode>
    <Todo />
  </StrictMode>
);

ソースコード

Todo.jsx(旧)

Todo.jsx
import { useState } from "react";
import "./styles.css";

export const Todo = () => {
  const [todoText, setTodoText] = useState("");
  const [incompleteTodos, setIncompleteTodos] = useState([
    "TODOです1",
    "TODOです2",
  ]);
  const [completeTodos, setCompleteTodos] = useState([
    "TODOでした1",
    "TODOでした2",
  ]);

  const onChangeTodoText = (event) => setTodoText(event.target.value);

  const onClickAdd = () => {
    if (todoText === "") {
      return;
    } else {
      const newTodos = [...incompleteTodos, todoText];
      setIncompleteTodos(newTodos);
      setTodoText("");
    }
  };
   const onClickDelete = (index) => {
    const newTodos = [...incompleteTodos];
    newTodos.splice(index, 1);
    setIncompleteTodos(newTodos);
  };

  const onClickComplete = () => {
    const newIncompleteTodos = [...incompleteTodos];
    newIncompleteTodos.splice(index, 1);
 
    const newCompleteTodos = [...completeTodos, incompleteTodos[index]];
 
    setIncompleteTodos(newIncompleteTodos);
    setCompleteTodos(newCompleteTodos);
  };

  return (
    <>
      <div className="input-area">
        <input
          placeholder="TODOを入力"
          value={todoText}
          onChange={onChangeTodoText}
        ></input>
        <button onClick={onClickAdd}>追加</button>
      </div>
      <div className="incomplete-area">
        <p className="title">未完了のTODO</p>
        <ul>    
          {incompleteTodos.map((todo, index) => {
            return (
              <li key={todo}>
                <div className="list-row">
                  <p>{todo}</p>
                  <button onClick={() => onClickComplete(index)}>完了</button>
                  <button onClick={() => onClickDelete(index)}>削除</button>
                </div>
              </li>
            );
          })}
        </ul>
      </div>
      <div className="complete-area">
        <p className="title">完了のTODO</p>
        <ul>
          {completeTodos.map((todo) => {
            return (
              <li>
                <div className="list-row">
                  <p>{todo}</p>
                  <button>戻す</button>
                </div>
              </li>
            );
          })}
        </ul>
      </div>
    </>
  );
};

Todo.jsx

Todo.jsx
import { useState } from "react";
import "./styles.css";

export const Todo = () => {
  const [todoText, setTodoText] = useState("");
  const [incompleteTodos, setIncompleteTodos] = useState([
    "TODOです1",
    "TODOです2",
  ]);
  const [completeTodos, setCompleteTodos] = useState([
    "TODOでした1",
    "TODOでした2",
  ]);

  const onChangeTodoText = (event) => setTodoText(event.target.value);

  const onClickAdd = () => {
    if (todoText === "") {
      return;
    } else {
      const newTodos = [...incompleteTodos, todoText];
      setIncompleteTodos(newTodos);
      setTodoText("");
    }
  };
   const onClickDelete = (index) => {
    const newTodos = [...incompleteTodos];
    newTodos.splice(index, 1);
    setIncompleteTodos(newTodos);
  };

  const onClickComplete = () => {
    const newIncompleteTodos = [...incompleteTodos];
    newIncompleteTodos.splice(index, 1);
 
    const newCompleteTodos = [...completeTodos, incompleteTodos[index]];
 
    setIncompleteTodos(newIncompleteTodos);
    setCompleteTodos(newCompleteTodos);
  };

+ const onClickBack = (index) => {
+   const newCompleteTodos = [...completeTodos];
+   newCompleteTodos.splice(index, 1);
+
+   const newIncompleteTodos = [...incompleteTodos, completeTodos[index]];
+
+   setCompleteTodos(newCompleteTodos);
+   setIncompleteTodos(newIncompleteTodos);
+ };

  return (
    <>
      <div className="input-area">
        <input
          placeholder="TODOを入力"
          value={todoText}
          onChange={onChangeTodoText}
        ></input>
        <button onClick={onClickAdd}>追加</button>
      </div>
      <div className="incomplete-area">
        <p className="title">未完了のTODO</p>
        <ul>    
          {incompleteTodos.map((todo, index) => {
            return (
              <li key={todo}>
                <div className="list-row">
                  <p>{todo}</p>
                  <button onClick={() => onClickComplete(index)}>完了</button>
                  <button onClick={() => onClickDelete(index)}>削除</button>
                </div>
              </li>
            );
          })}
        </ul>
      </div>
      <div className="complete-area">
        <p className="title">完了のTODO</p>
        <ul>
-         {completeTodos.map((todo) => {
+         {completeTodos.map((todo, index) => {
            return (
              <li>
                <div className="list-row">
                  <p>{todo}</p>
-                 <button>戻す</button>
+                 <button onClick={() => onClickBack(index)}>戻す</button>
                </div>
              </li>
            );
          })}
        </ul>
      </div>
    </>
  );
};

解説

目的

  • buttonタグ(戻す)を押下した時に、配列completeTodosの任意の要素を削除する
  • buttonタグ(戻す)を押下した時に、配列incompleteTodosの任意の要素を追加する

コーディング

  1. buttonタグ(戻す)を押下した際に発火する、onClickイベントを設定する

    Todo.jsx
    -                 <button>完了</button>
    +                 <button onClick={() => onClickBack(index)}>完了</button>
    
  2. onClickイベントで呼び出される関数をonClickBackとして設定する

    Todo.jsx
    +  const onClickBack = () => {
    + };
    
  3. 配列completeTodosの任意の項目を指定するには、配列completeTodos内の何番目の配列かを見分けられれば良い
    =配列のindexを取得する

    Todo.jsx
    -         {completeTodos.map((todo) => {        
    +         {completeTodos.map((todo, index) => {
    
  4. onClickBackindexを関数の引数として設定する

    Todo.jsx
    +  const onClickBack = (index) => {
    + };
    
  5. onCkickindexを関数の引数として設定する
    なぜ、onClick={onClickBack(index)と記載せずに、onClick={() => onClickBack(index)と記載するかはこちらを参照

    Todo.jsx
    -                 <button>完了</button>
    +                 <button onClick={() => onClickBack(index))}>完了</button>
    
  6. 最新の未完了の配列completeTodosnewCompleteTodosとして定義する(コピーする)

    Todo.jsx
      const onClickBack = () => {
    +   const newCompleteTodos = [...completeTodos];
    
  7. spliceメソッドを使って、渡ってきた第一引数indexから第二引数1番目を削除する

    Todo.jsx
      const onClickBack = () => {
        const newCompleteTodos = [...completeTodos];
    +   newCompleteTodos.splice(index, 1);
    
  8. 最新の完了の配列incompleteTodosnewIncompleteTodosとして定義する(コピーする)

    Todo.jsx
      const onClickBack = () => {
        const newCompleteTodos = [...completeTodos];
        newCompleteTodos.splice(index, 1);
     
    +   const newIncompleteTodos = [...incompleteTodos];
    
  9. 配列incompleteTodoscompleteTodos内の任意の(index)の要素を追加する

    Todo.jsx
      const onClickBack = () => {
        const newCompleteTodos = [...completeTodos];
        newCompleteTodos.splice(index, 1);
     
    +   const newIncompleteTodos = [...incompleteTodos, completeTodos[index]];
    
  10. 配列newIncompleteTodosを、配列incompleteTodosの更新関数であるsetIncompleteTodosに引数として渡す
    =配列incompleteTodosを更新する

    Todo.jsx
      const onClickBack = () => {
        const newCompleteTodos = [...completeTodos];
        newCompleteTodos.splice(index, 1);
     
        const newIncompleteTodos = [...incompleteTodos, completeTodos[index]];
     
    +   setIncompleteTodos(newIncompleteTodos);
    
  11. 配列newIncompleteTodosを、配列completeTodosの更新関数であるsetCompleteTodosに引数として渡す
    =配列completeTodosを更新する

    Todo.jsx
      const onClickBack = () => {
        const newCompleteTodos = [...completeTodos];
        newCompleteTodos.splice(index, 1);
     
        const newIncompleteTodos = [...incompleteTodos, completeTodos[index]];
     
        setIncompleteTodos(newIncompleteTodos);
    +   setCompleteTodos(newCompleteTodos);
      };
    

処理

  1. completeTodosに登録されている完了のTODOがリストとして表示されている
  2. ユーザーが完了ボタンを押下する
  3. onClickイベントが発火する
  4. {completeTodos.map((todo, index) => {...}}によってindexが各li要素に渡されているので、該当の要素がわかる
  5. () => onClickBack(index)が実行される
  6. 該当のindexonClickBackに渡る
  7. 最新の配列completeTodosnewCompleteTodosに渡す(コピーする)
  8. spliceメソッドを使って、newCompleteTodosの第一引数indexから第二引数1番目を削除する
  9. 最新の配列incompleteTodosnewIncompleteTodosに渡し(コピーし)、該当のindexを配列completeTodos内の要素を追加する
  10. newCompleteTodosを更新関数setCompleteTodosに渡す
  11. completeTodosが更新される
  12. Reactの再レンダリングがトリガーされる
  13. newIncompleteTodosを更新関数setIncompleteTodosに渡す
  14. incompleteTodosが更新される
  15. Reactの再レンダリングがトリガーされる
  16. buttonタグ(戻す)を押下した時に、配列completeTodosの任意の要素が削除・出力される

イメージ

Todo.jsx(旧)

image.png

Todo.jsx

image.png

参考リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?