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完全攻略ガイド ~制御構文とフォームの制御~

Last updated at Posted at 2025-10-06

参考教材

制御構文とフォームの制御

配列のリスト表示

//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>
    </>
  );
};

2025-10-02 0.26の画像.jpeg

return (
    <>
      <h3>配列の操作</h3>
      <ul>
        {/* mapは式なのでJSX内に直接書ける */}
        {animals.map((animal) => <li>Hello, {animal}</li>)}
      </ul>
    </>
  );

2025-10-02 0.29の画像.jpeg

2025-10-02 0.30の画像.jpeg

[重要]リストには必ずキーを設定しよう

return (
    <>
      <h3>配列の操作</h3>
      <ul>
        {/* mapは式なのでJSX内に直接書ける */}
        {animals.map((animal) => <li>Hello, {animal}</li>)}
      </ul>
    </>
  );

2025-10-02 0.32の画像.jpeg

コンソールでは(上記画像)のエラーが出ている。意味は配列の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>
  }
})}

2025-10-06 19.00の画像.jpeg


三項演算子

オススメ

//"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>

2025-10-06 19.30の画像.jpeg

Dog以外のときはfalseが出る


.map((animal) => {
  return <li key={animal}>{
    animal
  }{animal === "Dog" && ""}</li>

2025-10-06 19.00の画像.jpeg

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>
    </>
  )
}

2025-10-06 19.46の画像.jpeg

コンポーネントのリファクタリング

コードの整理をするためコンポーネントを分割する

Example.jsx
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;
components/AnimalList.jsx
// リスト形式の表示を担うコンポーネント
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;
components/AnimalItem.jsx
// 追加要素を担うコンポーネント
const AnimalItem = ({animal}) => {
  return (
    <li>
      {animal}
      {animal === "Dog" && ""}
    </li>
  )
};

export default AnimalItem;
components/AnimalFilter.jsx
// 入力欄の出力を担うコンポーネント
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>

2025-10-06 21.43の画像.jpeg

まずは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>

2025-10-06 22.17の画像.jpeg

Todoアプリを作ってみよう

Example.jsx
import Todo from "./components/Todo";

const Example = () => {
  return (
    <>
     <h2>Reminder</h2>
     <Todo />
    </>
  );
};

export default Example;
components/Todo.jsx
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;
components/TodoList.jsx
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;
components/TodoForm.jsx
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;

2025-10-07 16.19の画像.jpeg

追加機能① エンターボタンで入力値が追加されるようにする

components/TodoForm.jsx
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が省略されているため、現在開いているページにリクエストを送信して、再度そのページでリロードする役割がある。

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?