実施条件
[React][L3] テキストボックスの内容を出力するを理解していること
環境
MacBook Pro (2.3 GHz 8コアIntel Core i9)
macOS 14.0(23A344)
Homebrew 4.3.8
gh 2.52.0
ソースコードの前に
フォルダ構成
├── package.json
├── public/
│ └── index.html
├── src/
│ ├── index.jsx
│ ├── Todo.jsx
│ └── styles.css
│
index.html
<!DOCTYPE html>
<html lang="en">
<head> </head>
<body>
<div id="root"></div>
</body>
</html>
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(旧)
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("");
}
};
return (
<>
<div className="input-area">
<input placeholder="TODOを入力"></input>
<input placeholder="TODOを入力" value={todoText} onChange={onChangeTodoText}></input>
<button>追加</button>
<button onClick={onClickAdd}>追加</button>
</div>
<div className="incomplete-area">
<p className="title">未完了のTODO</p>
<ul>
{incompleteTodos.map((todo) => {
return (
<li key={todo}>
<div className="list-row">
<p>{todo}</p>
<button>完了</button>
<button>削除</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
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);
+ };
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) => {
+ {incompleteTodos.map((todo, index) => {
return (
<li key={todo}>
<div className="list-row">
<p>{todo}</p>
<button>完了</button>
- <button>削除</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>
</>
);
};
解説
目的
-
buttonタグ(削除)を押下した時に、配列incompleteTodosの任意の要素を削除する
コーディング
-
buttonタグ(削除)を押下した際に発火する、onClickイベントを設定するTodo.jsx- <button>削除</button> + <button onClick={onClickDelete)}>削除</button> -
onClickイベントで呼び出される関数をonClickDeleteとして設定するTodo.jsx+ const onClickDelete = () => { + }; -
配列
incompleteTodosの任意の項目を指定するには、配列incompleteTodos内の何番目の配列かを見分けられれば良い
=配列のindexを取得するTodo.jsx- {incompleteTodos.map((todo) => { + {incompleteTodos.map((todo, index) => { -
onClickDeleteにindexを関数の引数として設定するTodo.jsx+ const onClickDelete = (index) => { + }; -
onCkickにindexを関数の引数として設定する
なぜ、onClick={onClickDelete(index)と記載せずに、onClick={() => onClickDelete(index)と記載するかはこちらを参照Todo.jsx- <button>削除</button> + <button onClick={() => onClickDelete(index))}>削除</button> -
最新の配列
incompleteTodosをnewTodosとして定義するTodo.jsxconst onClickDelete = (index) => { + const newTodos = [...incompleteTodos]; }; -
spliceメソッドを使って、渡ってきた第一引数indexから第二引数1番目を削除するTodo.jsxconst onClickDelete = (index) => { const newTodos = [...incompleteTodos]; + newTodos.splice(index, 1); }; -
newTodosを配列incompleteTodosの更新関数であるsetIncompleteTodosに引数として渡す
= 配列incompleteTodosを更新するTodo.jsxconst onClickDelete = (index) => { const newTodos = [...incompleteTodos]; newTodos.splice(index, 1); + setIncompleteTodos(newTodos); };
処理
-
incompleteTodosに登録されているTODOがリストとして表示されている - ユーザーが
削除ボタンを押下する -
onClickイベントが発火する {incompleteTodos.map((todo, index) => {...}}によってindexが各li要素に渡されているので、該当の要素がわかる-
() => onClickDelete(index)が実行される - 該当の
indexがonClickDeleteに渡る - 最新の配列
incompleteTodosをnewTodosに渡す(コピーする) -
spliceメソッドを使って、newTodosの第一引数indexから第二引数1番目を削除する -
newTodosを更新関数setIncompleteTodosに渡す -
incompleteTodosが更新される - Reactの再レンダリングがトリガーされる
-
buttonタグ(削除)を押下した時に、配列incompleteTodosの任意の要素が削除される

