実施条件
[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
を関数n引数として設定するTodo.jsx+ const onClickDelete = (index) => { + };
-
onCkick
にindex
を関数の引数として設定する
なぜ、onClick={onClickDelete(index)
と記載せずに、onClick={() => onClickDelete(index)
と記載するかはこちらを参照Todo.jsx- <button>削除</button> + <button onClick={() => onClickDelete(index))}>削除</button>
-
最新の
todoText
の値を、配列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
の任意の要素が削除される