はじめに
死ぬは言いすぎましたね、すいません
Reactはコンポーネントベースのライブラリで、宣言的なUIを作成できる便利なツールですが、基本的なHTMLの理解が足りないと詰むことがあります。
今回は、私がHTMLの知識不足であったことを理由に
Reactのレンダリング挙動でハマった事例を紹介します。
事例:簡単なタスク管理アプリ
以下のコードは、タスクを追加・削除する簡単なToDoアプリです。
import { useState } from "react";
const Example = () => {
const [input, setInput] = useState('');
const [tasks, setTasks] = useState([]);
const setInputValue = (e) => {
setInput(e.target.value);
}
const addTask = () => {
setTasks([...tasks, input]);
setInput('');
}
const doneTask = (e) => {
setTasks(tasks.filter((task) => task !== e.target.value));
}
return (
<>
<h1>Reminder</h1>
<input type="text" onChange={setInputValue} value={input}/>
<button onClick={addTask}>addTask</button>
{tasks.map((task) => (
<>
<p key={task}>{task}</p>
<button onClick={doneTask} value={task}>完了</button>
</>
))}
</>
);
};
export default Example;
以下のような挙動(※DB連携はしていないです)
修正前はどんな挙動でどんなコードだったか?
以下のようなコードでした
差分はinputとbuttonをformでラップしているかどうかの違いです
import { useState } from "react";
const Example = () => {
const [input, setInput] = useState('');
const [tasks, setTasks] = useState([]);
const setInputValue = (e) => {
setInput(e.target.value);
}
const addTask = () => {
setTasks([...tasks, input]);
setInput('');
}
const doneTask = (e) => {
setTasks(tasks.filter((task) => task !== e.target.value));
}
return (
<div style={{ textAlign: "center", paddingTop: "20px" }}>
<h1>Reminder</h1>
<form action="">
<input type="text" onChange={setInputValue} value={input}/>
<button onClick={addTask}>addTask</button>
</form>
</div>
);
};
export default Example;
挙動
原因
正常に動作するコードとの差分はformも有無なのでそこに原因があると推測
よく見るとURLにクエリが....(あ.....)
formタグはHTTPメソッドやactionを設定してページ遷移やデータの受け渡しを可能にするんでしたね
今回の場合クエリに空文字が渡されそのURLが再読み込みされるため
下の画像のトップレベルコンポーネントである
Example
が再実行されコンポーネント全体が再レンダリングされてしまいます。
そのため、タスクを追加しても初期化状態に戻ってしまうのです。
まとめ
Reactを使う際、以下のポイントに気をつけましょう。
-
form
を使用するときはonSubmit
や各属性を適切に使う。 -
HTMLの基本動作を理解していないと、Reactの挙動にハマることがある。
Reactを使う前に、HTMLとDOMの基本的な動作を理解しておくことが、スムーズな開発につながります!!