参考教材
制御構文とフォームの制御
配列のリスト表示
//mapを使った配列の中身を全て表示する方法
const animals = ["Dog", "Cat", "Rat"];
const Example = () => {
//Reactはfor文をあまり使わずmapなどの配列のメソッドをよく使う
const helloAnimals = animals.map((animal) => <li>Hello, {animal}</li>)
return (
<>
<h3>配列の操作</h3>
<ul>
<li>{animals[0]}</li>
<li>{animals[1]}</li>
<li>{animals[2]}</li>
{helloAnimals}
</ul>
</>
);
};
return (
<>
<h3>配列の操作</h3>
<ul>
{/* mapは式なのでJSX内に直接書ける */}
{animals.map((animal) => <li>Hello, {animal}</li>)}
</ul>
</>
);
[重要]リストには必ずキーを設定しよう
return (
<>
<h3>配列の操作</h3>
<ul>
{/* mapは式なのでJSX内に直接書ける */}
{animals.map((animal) => <li>Hello, {animal}</li>)}
</ul>
</>
);
コンソールでは(上記画像)のエラーが出ている。意味は配列のEach child(子要素)に"key"がないですよ〜。という内容
{animals.map((animal) => <li key={animal} >Hello, {animal}</li>)}
keyは一意に定まる値をつける。
前提知識
ReactはReact要素ツリーの差分検出処理をしてDOMを更新している
子要素にkeyを持たせると、Reactはどの要素が変更、追加、削除してのかを識別できるようになるため、差分のみを更新することが可能になる
keyをつける注意点
・キーには必ず任意の値を設定する
・キーに設定した値は変更しない
・配列のインデックスはなるべく使わない
配列のフィルターメソッド
import { useState } from "react";
const animals = ["Dog", "Cat", "Rat"];
const Example = () => {
const [ filterVal, setFilterVal ] = useState("");
return (
<>
<h3>配列のフィルター</h3>
<input type="text" value={filterVal} onChange={(e) => setFilterVal(e.target.value)}/>
<ul>
{animals
// 第一引数(animal)はanimals配列の各要素が入ってくる
.filter(animal => animal.indexOf(filterVal) !== -1)
.map((animal) => (
<li>{animal}</li>
))}
</ul>
</>
);
};
①filterのコールバック関数の値がTrueの場合は新しい配列に含めて、Falseの場合は新しい配列に含めないという制御なので、(animal => 〇〇)の〇〇の箇所は、入力欄に入力された文字と一致かどうか(True,False)かを返す場所になっている
=====
②indexOfの特性で、一致するか判定する値が(-1)を返した場合は、「一致する文字列が見つかりませんでした」になる。逆に戻り値が(-1)以外の場合は、「一致した箇所が見つかりました」になる。
条件分岐を設ける方法
if文
//"Dog"に★をつけるif文
.map((animal) => {
if(animal === "Dog"){
return <li key={animal}>{animal}★</li>
} else {
return <li key={animal}>{animal}</li>
}
})}
三項演算子
オススメ
//"Dog"に★をつける三項演算子
.map((animal) => {
return <li key={animal}>{
animal === "Dog"
? animal + "★"
: animal
}</li>
}
プログラミングをする際、なるべく重複を少なくしたほうがいい。変更箇所が出たら1箇所だけ直せばいいので三項演算子の方がメンテナンスしやすい。
//これでも可
.map((animal) => {
return <li key={animal}>{
animal + (animal === "Dog"
? "★"
: ""
)
}</li>
}
&&
.map((animal) => {
return <li key={animal}>{
animal + (animal === "Dog" && "★")
}</li>
Dog以外のときはfalseが出る
.map((animal) => {
return <li key={animal}>{
animal
}{animal === "Dog" && "★"}</li>
Reactだと{}の中に書けば、真偽値が画面上に表示されなくなる。trueの時のみ&&条件で★が出る。
??(null合体演算子)
const Example = () => {
const animals = ["Dog", "Cat", null, "Rat"];
return (
<>
<ul>
{animals
.filter((animal) => {
// 左側の値が"null"か"undefined"の時、右側の値を返す
const animalStr = animal ?? "";
const isMatch = animalStr.indexOf(filterVal) !== -1;
return isMatch;
})
.map((animal) => {
return <li key={animal}>{
animal ?? "null,undefinedでした"
}{animal === "Dog" && "★"}</li>
})}
</ul>
</>
)
}
コンポーネントのリファクタリング
コードの整理をするためコンポーネントを分割する
mport { useState } from "react";
import AnimalList from "./conponents/AnimalList";
import AnimalFilter from "./conponents/AnimalFilter"
const Example = () => {
const animals = ["Dog", "Cat", "Rat"];
const [filterVal, setFilterVal] = useState("");
const filterdAnimals = animals
.filter((animal) => {
const isMatch = animal.indexOf(filterVal) !== -1;
return isMatch;
})
return (
<>
{/* 配列の0番目にfilterValを渡して、1番目にsetFilterValの関数を渡す */}
<AnimalFilter filterState={[filterVal, setFilterVal]}/>
<AnimalList animals={filterdAnimals}/>
</>
);
};
export default Example;
// リスト形式の表示を担うコンポーネント
import AnimalItem from "./AnimalItem";
const AnimalList = ({animals}) => {
//animalsの配列が空だった場合、「アニマルが見つかりません」と表示する
if(animals.length === 0){
return <h3>アニマルが見つかりません</h3>
}
return(
<ul>
{animals
.map((animal) => {
return (
<AnimalItem animal={animal} key={animal}/>
);
})}
</ul>
)
}
export default AnimalList;
// 追加要素を担うコンポーネント
const AnimalItem = ({animal}) => {
return (
<li>
{animal}
{animal === "Dog" && "★"}
</li>
)
};
export default AnimalItem;
// 入力欄の出力を担うコンポーネント
const AnimalFilter = ({filterState}) => {
const [filterVal, setFilterVal] = filterState;
return (
<input
type="text"
value={filterVal}
onChange={(e) => setFilterVal(e.target.value)}
/>
)
};
export default AnimalFilter;
※リファクタリング後は問題なく動くかを確認すること(コンソールも)
//animalsの配列が空だった場合、「アニマルが見つかりません」と表示する
if(animals.length === 0){
return <h3>アニマルが見つかりません</h3>
まずは1つのコンポーネントでコードを記述してみて、完成後に役割別にコンポーネントのリファクタリングをするのがおすすめ
Form
input
<div>
{/**labelはinput要素に連携して使う */}
{/**htmlForとidの値を合わせると、ラベルをクリックするとinput要素にフォーカスが当たる */}
<label htmlFor="456">ラベル</label>
<div>
{/* inputはvalueとonChageに対してStateを連携させる記述をよく使う*/}
<input
id="456"
placeholder="こんにちは"
value={val}
onChange={(e) => setVal(e.target.value)}
/>
</div>
</div>
Todoアプリを作ってみよう
import Todo from "./components/Todo";
const Example = () => {
return (
<>
<h2>Reminder</h2>
<Todo />
</>
);
};
export default Example;
import TodoList from "./TodoList";
import TodoForm from "./TodoForm";
import { useState } from "react";
const Todo = () => {
const todosList = [
{
id: 1,
content: "店予約する",
},
{
id: 2,
content: "卵買う",
},
{
id: 3,
content: "郵便出す",
},
];
const [todos, setTodos] = useState(todosList);
//引数にidを設定、渡ってきてidとtodoListのidが一致するならidを削除するロジックを組む
const deleteTodo = (id) => {
const newTodos = todos.filter((todos) => {
return todos.id !== id;
})
setTodos(newTodos);
};
//TodoFormで新しく作成したTodoを、todosに入れる必要がある
const createTodo = (todo) => {
setTodos([...todos, todo])
}
return (
<>
<TodoList todos={todos} deleteTodo={deleteTodo}/>
<TodoForm createTodo={createTodo}/>
</>
)
};
export default Todo;
const TodoList = ({todos, deleteTodo}) => {
const complete = (id) => {
deleteTodo(id);
};
return (
<div>
{todos.map(todo => {
return (
<div key={todo.id}>
<button onClick={() => complete(todo.id)}>完了</button>
<span>{todo.content}</span>
</div>
)
})}
</div>
)
}
export default TodoList;
import { useState } from "react";
const TodoForm = ({createTodo}) => {
//入力欄の状態を監視するState
const [ enteredTodo, setEnteredTodo ] = useState("");
const addTodo = (e) => {
//ブラウザのデフォルト動作を止めるメソッド
e.preventDefault();
const newTodo = {
//適当な値で乱数を作成
id: Math.floor(Math.random() * 1e5),
content: enteredTodo,
}
createTodo(newTodo);
//値を入力後に入力欄を空にする
setEnteredTodo("");
};
return (
<div>
<form onSubmit={addTodo}>
<input type="text" value={enteredTodo} onChange={(e) => setEnteredTodo(e.target.value)}/>
<button>追加</button>
</form>
</div>
)
}
export default TodoForm;
追加機能① エンターボタンで入力値が追加されるようにする
const addTodo = (e) => {
//ブラウザのデフォルト動作を止めるメソッド
e.preventDefault();
}
return (
<div>
<form onSubmit={addTodo}>
<input type="text" value={enteredTodo} onChange={(e) => setEnteredTodo(e.target.value)}/>
<button>追加</button>
</form>
</div>
)
formタグで囲んであげると、エンターが押されたタイミングで、formのsubmitイベントが実行されてTodoを追加する
ーー
⚠️formはデフォルトの操作で、action属性に指定されたURLにリクエストを送って、そのページに遷移するという機能を持っている。今回のコードはactionが省略されているため、現在開いているページにリクエストを送信して、再度そのページでリロードする役割がある。









