Reactを利用してコーディングしている際に以前理解したはずのReact Hooks、props、分岐、リスト表示などの機能や記述方法を忘れることはありませんか?また他のフレームワークを使っていて久しぶりにReactを使う場面が来た時にReactの場合はどうやって記述するんだっけと混乱したことはないですか?

そんな人のためにReact用のシンプルコードのチートシートを作成しました。

関数コンポーネント


function App(){
  return <h1>Hello World</h1>
} 

export default App;

export default function App() {
  return <h1>Hello World</h1>
} 

const App = () => {
  return <h1>Hello World</h1>
} 

export default App;

下記はNGでエラーメッセージが表示されます。”Only expressions, functions or classes are allowed as the default export”


export default const App = () => {
  return <h1>Hello World</h1>
} 

Fragments

Reactではルートの要素が1つである必要があるため下記のコードではエラーが発生。


function App() {
  return (
    <h1>Hello World</h1>
    <p>Fragment</p>
  );
} 

ルートの要素が一つでない場合はFragmentを利用することができます。


import { Fragment } from 'react';

function App() {
  return (
    <Fragment>
      <h1>Hello World</h1>
      <p>Fragment</p>
    </Fragment>
  );
}

<Fragment></Fragment>の省略形<></>を利用することも可能です。


function App() {
  return (
    <>
      <h1>Hello World</h1>
      <p>Fragment</p>
    </>
  );
}

div要素など他の要素でラップすることも可能ですがdiv要素がブラウザ上に表示されます。Fragmentは追加の要素が表示されません。


function App() {
  return (
    <div>
      <h1>Hello World</h1>
      <p>Fragment</p>
    </div>
  );
}

テンプレートリテラル


const user_name = `${user.firstName} ${user.lastName}`;

//テンプレートリテラルを利用しない場合
const userName = user.firstName + " " + user.lastName;

CSSの設定

class属性

class属性はclassではなくclassNameを利用します。


import './App.css';

function App() {
  return <h1 className="App">Hello World</h1>;
}

//App.css
.App {
  text-align: center;
}

style属性 inline

style属性を設定したい場合は下記のように設定を行います。text-alignプロパティのような”-“が入っているものはキャメルケースでtextAlignに変更する必要があります。


function App() {
  return <h1 style={{ textAlign: 'center' }}>Hello World</h1>;
}

textAlignを利用せずシングルクオテーションで囲んだ場合はWarning(警告)が表示されます。”Warning: Unsupported style property text-align. Did you mean textAlign?”


function App() {
  return <h1 style={{ 'text-align': 'center' }}>Hello World</h1>;
}

style属性

オブジェクトとして別に定義して設定することもできます。


const appStyle = {
  textAlign: 'center',
};

function App() {
  return <h1 style={appStyle}>Hello World</h1>;
}

export default App;

コンポーネントのexport/import

default export


function User() {
  return <h2>ユーザ</h2>;
}

export default User;

import User from './User';

function App() {
  return (
    <>
      <h1>Hello World</h1>
      <User />
    </>
  );
}

export default App;

default exportではimportしたコンポーネントの名前を任意の名前に設定することができます。


import UserComponent from './User';

function App() {
  return (
    <>
      <h1>Hello World</h1>
      <UserComponent />
    </>
  );
}

export default App;

named export


export function User() {
  return <h2>ユーザ</h2>;
}

import { User } from './User';

function App() {
  return (
    <>
      <h1>Hello World</h1>
      <User />
    </>
  );
}

export default App;

importしたコンポーネントの名前を変更したい場合はasを利用します。


import { User as UseComponent } from './User';

function App() {
  return (
    <>
      <h1>Hello World</h1>
      <UseComponent />
    </>
  );
}

export default App;

Props

1つの場合


function User(props) {
  return (
    <>
      <h2>ユーザ</h2>
      <p>名前:{props.name}</p>
    </>
  );
}

export default User;

import User from './User';

function App() {
  return <User name="John Doe" />;
}

複数の場合


function User(props) {
  return (
    <>
      <h2>ユーザ</h2>
      <p>名前:{props.name}</p>
      <p>年齢:{props.age}</p>
    </>
  );
}

export default User;

※props.XXXを利用するよりどのpropsをコンポーネント内で利用しているか明確になる分割代入の利用がおすすめです。


import User from './User';

function App() {
  return <User name="John Doe" age="30" />
}

分割代入を利用


function User({ name, age }) {
  return (
    <>
      <h2>ユーザ</h2>
      <p>名前:{name}</p>
      <p>年齢:{age}</p>
    </>
  );
}

export default User;

function User(props) {
  const { name, age } = props;
  return (
    <>
      <h2>ユーザ</h2>
      <p>名前:{name}</p>
      <p>年齢:{age}</p>
    </>
  );
}

export default User;

Spread Operatorの利用

propsを子コンポーネントに渡す時にspread operator(スプレッド構文)を利用することもできます。


import User from './User';

function App() {
  const props = { name: 'John', age: 20 };

  return <User {...props} />;
}

function User(props) {
  return (
    <>
      <h2>ユーザ</h2>
      <p>名前:{props.name}</p>
      <p>年齢:{props.age}</p>
    </>
  );
}

export default User;

children

コンポーネントタグの中に入れたコンテンツはpropsとして子コンポーネントに渡すことができます。


import User from './User';

function App() {
  return <User>Hello User</User>;
}

function User(props) {
  return (
    <>
      <h2>ユーザ</h2>
      <p>{props.children}</p>
    </>
  );
}

export default User;

デフォルト値の設定

親コンポーネントからpropsで値を渡されない場合にはデフォルト値が利用されます。


function User({ name, age = '20' }) {
  return (
    <>
      <h2>ユーザ</h2>
      <p>名前:{name}</p>
      <p>年齢:{age}</p>
    </>
  );
}

export default User;

import User from './User';

function App() {
  return <User name="John Doe" />;
}

export default App;

booleanのprops


import User from './User';

function App() {
  return <User showError />;
}

export default App;

showError={true}となるのでコンソールには”エラーが発生しています。”と表示されます。


function User({ showError }) {
  if (showError) console.log('エラーが発生しています。');
  return <h2>ユーザ</h2>;
}

export default User;

リスト表示(map, filter関数)

配列


function App() {
  const users = ['John', 'Joe', 'Kevin'];
  return (
    <ul>
      {users.map((user) => (
        <li key={user}>{user}</li>
      ))}
    </ul>
  );
}

配列+index


function App() {
  const users = ['John', 'Joe', 'Kevin'];
  return (
    <ul>
      {users.map((user,index) => (
        <li key={index}>{user}</li>
      ))}
    </ul>
  );
}

※実際にkeyにはindexではなく配列で一意となるidなどの値を利用します。

オブジェクト


function App() {
  const users = [
    { name: 'John', age: 20 },
    { name: 'Joe', age: 24 },
    { name: 'Kevin', age: 22 },
  ];
  return (
    <ul>
      {users.map((user, index) => (
        <li key={index}>{user.name}</li>
      ))}
    </ul>
  );
}

オブジェクト+Component


function User(props) {
  return (
    <li>
      名前:{props.name} 年齢:{props.age}
    </li>
  );
}

export default User;

import User from './User';

function App() {
  const users = [
    { name: 'John', age: 20 },
    { name: 'Joe', age: 24 },
    { name: 'Kevin', age: 22 },
  ];
  return (
    <ul>
      {users.map((user, index) => (
        <User key={index} name={user.name} age={user.age} />
      ))}
    </ul>
  );
}

export default App;

filter


function App() {
  const tasks = [
    {
      id: 1,
      title: 'Call Client',
      complete: false,
    },
    {
      id: 2,
      title: 'Workout',
      complete: false,
    },
    {
      id: 3,
      title: 'Buy Snack',
      complete: true,
    },
  ];

  const UnCompleteTasks = tasks.filter((task) => task.complete === false);

  return (
    <>
      <h1>UnComplete Tasks</h1>
      <ul>
        {UnCompleteTasks.map((task) => (
          <li key={task.id}>{task.title}</li>
        ))}
      </ul>
    </>
  );
}

export default App;

条件分岐(conditional)

if文


const AdminDashboard = () => <h1>管理者用ダッシュボード</h1>;
const Dashboard = () => <h1>ユーザ用ダッシュボード</h1>;

function App() {
  const user = {
    admin: false,
    name: 'John',
  };

  if (user.admin) return <AdminDashboard />

  return <Dashboard />
}

export default App;

三項演算子


const AdminDashboard = () => <h1>管理者用ダッシュボード</h1>;
const Dashboard = () => <h1>ユーザ用ダッシュボード</h1>;

function App() {
  const user = {
    admin: false,
    name: 'John',
  };
  return <>{user.admin ? <AdminDashboard /> : <Dashboard />}</>
}

export default App;

論理積(&&)

user.adminがtrueの場合のみ”あなたは管理者です。”が表示されます。


const Dashboard = () => <h1>ダッシュボード</h1>;

function App() {
  const user = {
    admin: true,
    name: 'John',
  };

  return (
    <>
      {user.admin && <p>あなたは管理者です。</p>}
      <Dashboard />
    </>
  );
}

export default App;

論理和(||)

user.adminがfalseの場合のみ”あなたは管理者ではありません。”が表示されます。


const Dashboard = () => <h1>ダッシュボード</h1>;

function App() {
  const user = {
    admin: false,
    name: 'John',
  };

  return (
    <>
      {user.admin || <p>あなたは管理者ではありません。</p>}
      <Dashboard />
    </>
  );
}

export default App;

イベント

clickイベント


function App() {
  const handleClick = () => {
    console.log('Hello!');
  };
  return (
    <>
      <h1>Hello World</h1>
      <button onClick={handleClick}>Click</button>
    </>
  );
}

export default App;

//コンソールに表示される内容
Hello!

clickイベント(引数あり)

引数がある場合はアロー関数を利用して記述します。


function App() {
  const handleClick = (greeting) => {
    console.log(greeting);
  };
  return (
    <>
      <h1>Hello World</h1>
      <button onClick={() => handleClick('おはよう!')}>Click</button>
    </>
  );
}

export default App;

//コンソールに表示される内容
おやよう!

下記のように記述した場合はレンダリング直後にイベントが実行されます。


function App() {
  const handleClick = (greeting) => {
    console.log(greeting);
  };
  return (
    <>
      <h1>Hello World</h1>
      <button onClick={handleClick('おはよう!')}>Click</button>
    </>
  );
}

export default App;

//コンソールに表示される内容
おやよう!

clickイベント(インライン)


function App() {
  return (
    <>
      <h1>Hello World</h1>
      <button
        onClick={() => {
          console.log('Hello!');
        }}
      >
        Click
      </button>
    </>
  );
}

export default App;

//コンソールに表示される内容
Hello!

event情報の取得


function App() {
  const handleClick = (e) => {
    console.log(e.target);
  };
  return (
    <>
      <h1>Hello World</h1>
      <button onClick={handleClick}>Click</button>
    </>
  );
}

export default App;

//コンソールに表示される内容
<button>Click</button>

onChangeイベント

input要素に入力を行う度にイベントが発火されコンソールに入力した文字が表示されます。


function App() {
  const handleChange = (e) => {
    console.log(e.target.value);
  };
  return (
    <>
      <h1>onChange Event</h1>
      <input onChange={handleChange} />
    </>
  );
}

export default App;

onBlurイベント

input要素からフォーカスを外すとイベントが発火されコンソールに入力した文字列が表示されます。


function App() {
  const handleBlur = (e) => {
    console.log(e.target.value);
  };
  return (
    <>
      <h1>onBlur Event</h1>
      <input onBlur={handleBlur} />
    </>
  );
}

export default App;

Hooks

useState


import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  return (
    <>
      <div>Count:{count}</div>
      <button onClick={increment}>Up</button>
    </>
  );
}

export default Counter;

useState(preValueを利用)

previouse valueを利用したい場合は下記のように記述できます。


import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount((prevCount) => prevCount + 1);
  };

  return (
    <>
      <div>Count:{count}</div>
      <button onClick={increment}>Up</button>
    </>
  );
}

export default Counter;

useState(インライン)


import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <>
      <div>Count:{count}</div>
      <button onClick={() => setCount(count + 1)}>Up</button>
    </>
  );
}

export default Counter;

useEffect

外部リソース(JSONPlaceHoler)からuseEffect内でユーザ情報を取得してブラウザ上に表示されます。useEffectの依存配列が[]空なのでマウント後に一度だけuseEffectの中身が実行されます。


import { useEffect, useState } from 'react';

function App() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/users')
      .then((response) => response.json())
      .then((users) => setUsers(users));
  }, []);

  return (
    <>
      <h1>ユーザ一覧</h1>
      <ul>
        {users.map((user) => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </>
  );
}

export default App;

useEffect+async,await

async, awaitを利用した場合は下記のように記述できます。


import { useEffect, useState } from 'react';

function App() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    const fetchUsers = async () => {
      const response = await fetch(
        'https://jsonplaceholder.typicode.com/users'
      );
      const users = await response.json();
      setUsers(users);
    };
    fetchUsers();
  }, []);

  return (
    <>
      <h1>ユーザ一覧</h1>
      <ul>
        {users.map((user) => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </>
  );
}

export default App;

useEffectと依存配列

依存配列に設定した変数が更新されるとuseEffectの中身が実行されます。

コンポーネントのマウント後にuseEffectの中身が実行され’Count Up’がコンソールに表示されます。その後はボタンを押すと’Count Up’がコンソールに表示されます。


import { useEffect, useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log('Count Up');
  }, [count]);

  return (
    <>
      <div>Count:{count}</div>
      <button onClick={() => setCount(count + 1)}>Up</button>
    </>
  );
}

export default Counter;

useEffectとクリーンアップ

useEffectでsetIntervalを設定すると設定した間隔でsetIntervalのcallback関数が実行されます。returnに関数を設定することでアンマウント時にsetIntervalを削除する処理を行っています。イベントリスナーなどを利用している場合にはクリーンアップの処理を実行する必要があります。


import { useEffect } from 'react';

function Timer() {
  useEffect(() => {
    const id = setInterval(() => {
      console.log('working');
    }, 1000);
    return () => {
      clearInterval(id);
    };
  });
  return <h2>Timer</h2>;
}

export default Timer;

下記のように親コンポーネントから表示・非表示の切り替えが行える場合にクリーンアップ処理を行っていないとuseEffectの処理が非表示後の継続して実行されます。


import { useState } from 'react';
import Timer from './Timer';

function App() {
  const [show, setShow] = useState(true);

  return (
    <>
      {show && <Timer />}
      <button onClick={() => setShow(!show)}>Toggle</button>
    </>
  );
}

export default App;

複数のuseEffect

useEffectは1つのコンポーネントに1つではなく複数設定することができます。


import { useEffect } from 'react';

function App() {
  useEffect(() => {
    console.log('mounted One');
  }, []);
  useEffect(() => {
    console.log('mounted Two');
  }, []);

  return <h1>Hello World!</h1>;
}

export default App;

useEffect +EventListener


import { useEffect, useState } from 'react';

function App() {
  const [windowSize, setWindowSize] = useState({
    innerWidth: undefined,
    innerHeight: undefined,
  });

  useEffect(() => {
    function handleResize() {
      setWindowSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    }

    handleResize();
    window.addEventListener('resize', handleResize);

    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return (
    <>
      <h1>コンテンツ領域のサイズ</h1>
      <p>フラウザのコンテンツ領域の幅: {windowSize.width}px</p>
      <p>フラウザのコンテンツ領域の高さ: {windowSize.height}px</p>
    </>
  );
}

export default App;

※本文書の”カスタムフックuseResizeHook”で上記コードをカスタムフックで書き換えています。

useRef

useRefを利用して要素に直接をアクセスすることができるためinputに文字を入力し、input要素にフォーカスを当てることができます。


const { useRef } = require('react');

function App() {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.value = 'useRef';
    inputRef.current.focus();
    console.log(inputRef.current);
  };

  return (
    <>
      <h1>UseRef</h1>
      <div>
        <input ref={inputRef} name="name" />
      </div>
      <button onClick={handleClick}>Focus</button>
    </>
  );
}

export default App;

//コンソールに表示される内容
<input name="name">

useReducer

useStateと同様にデータを管理することができます。


import { useReducer } from 'react';

const initialState = {
  count: 0,
};

const reducer = (state, action) => {
  switch (action) {
    case 'INCREMENT':
      return { count: state.count + 1 };
    case 'DECREMENT':
      return { count: state.count - 1 };
    default:
      return state;
  }
};

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      <h2>Counter</h2>
      <p>カウント: {state.count}</p>
      <button onClick={() => dispatch('INCREMENT')}>+</button>
      <button onClick={() => dispatch('DECREMENT')}>-</button>
    </>
  );
}

export default Counter;

useContext

UserContext.Providerでラップされたコンポーネント以下ではUserContext.Providerから渡されたuserオブジェクトをuseContextを利用して下の階層のコンポーネントからアクセスすることができます。


import { createContext } from 'react';
import Content from './Content';

export const UserContext = createContext('');

function App() {
  const user = {
    name: 'John Doe',
    age: 30,
  };
  return (
    <UserContext.Provider value={user}>
      <h1>Hello World!</h1>
      <Content />
    </UserContext.Provider>
  );
}

export default App;

import { useContext } from 'react';
import { UserContext } from './App';

const Header = () => {
  const { name } = useContext(UserContext);
  return <p>Name: {name}</p>;
};

function Content() {
  return <Header />;
}

export default Content;

useCallback

コンポーネントが再レンダリングされると定義している関数は再作成されます。useCallbackによって関数をメモ化することで再作成を行わないようにすることができます。memoと一緒に利用することで関数をpropsとして受け取る子コンポーネントの不必要な再レンダリングをなくすことができます。

memoは親コンポーネントから渡されるpropsに変更がないかチェックを行い、変更がある場合のみ子コンポーネントの再レンダリングが行われます。Reactではmemoを利用しない場合は親コンポーネントが再レンダリングされるとその階層下にあるすべてのコンポーネントが再レンダリングされます。

resetCount関数にuseCallback Hookを設定します。”+”ボタンをクリックしてもresetCount関数が再作成されることがなくなります。


import { useState, useCallback } from 'react';
import Reset from './Reset';


function App() {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  const resetCount = useCallback(() => {
    setCount(0);
  }, []);

  return (
    <>
      <h1>Counter</h1>
      <p>count:{count}</p>
      <button onClick={increment}>+</button>
      <Reset resetCount={resetCount} />
    </>
  );
}

export default App;

Resetコンポーネントはmemoでラップしています。memoを利用しない場合はuseCallbackを設定しても”+”ボタンをクリックすると度にResetコンポーネントが再レンダリングされます。


import { memo } from 'react';

const Reset = memo((props) => {
  const { resetCount } = props;
  return <button onClick={resetCount}>Reset</button>;
});

export default Reset;

useCallback+依存配列

useCallback Hookは第二引数に依存配列を設定します。先ほどは[]空でしたが[count]を設定します。countが変化するとresetCount関数は再作成されるので”+”ボタンをクリックするとResetコンポーネントが再レンダリングされます。”Reset”ボタンを押しても再レンダリングされます。この例では結果的にuseCallbackを使わない時と同じ動きになります。


import { useState, useCallback } from 'react';
import Reset from './Reset';

function App() {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

const resetCount = useCallback(() => {
  setCount(0);
}, [count]);

  return (
    <>
      <h1>Counter</h1>
      <p>count:{count}</p>
      <button onClick={increment}>+</button>
      <Reset resetCount={resetCount} />
    </>
  );
}

export default App;

useMemo

useMemoは関数による計算結果をメモ化するHookです。依存配列を設定することで設定した変数に更新があった場合(CountOneが増えた)のみuseMemoが再計算されます。useMemoを設定しない場合はcountTwoが増えた場合も再計算が行われます。


import { useState, useMemo } from 'react';
// import Count from './Count';

function App() {
  const [countOne, setCountOne] = useState(0);
  const [countTwo, setCountTwo] = useState(0);

  const incrementOne = () => {
    setCountOne(countOne + 1);
  };

  const incrementTwo = () => {
    setCountTwo(countTwo + 1);
  };

  const doubleCountOne = useMemo(() => {
    return countOne * 2;
  }, [countOne]);

  return (
    <>
      <h1>Counter</h1>
      <p>Count One:{countOne}</p>
      <button onClick={incrementOne}>+</button>
      <p>Count Two:{countTwo}</p>
      <button onClick={incrementTwo}>+</button>
      <p>Double Count One: {doubleCountOne}</p>
    </>
  );
}

export default App;

useMemoの依存配列に何も指定しない場合は初回のレンダリング時に一度だけ計算を行いその後はcountOneが増えても同じ値がブラウザ上に表示されます。

useMemo+memo

memoと組み合わせることで不必要な再レンダリングをなくすことができます。

useMemoで設定した計算結果をpropsで渡す場合countOneが変更されるとuseMemoが再計算されるのでCountコンポーネントが再レンダリングされます。countTwoを変更してもCountコンポーネントの再レンダリングは行われません。


import { useState, useMemo } from 'react';
import Count from './Count';

function App() {
  const [countOne, setCountOne] = useState(0);
  const [countTwo, setCountTwo] = useState(0);

  const incrementOne = () => {
    setCountOne(countOne + 1);
  };

  const incrementTwo = () => {
    setCountTwo(countTwo + 1);
  };

  const doubleCountOne = useMemo(() => {
    return countOne * 2;
  }, [countOne]);

  // useMemoを使わない場合
  // const doubleCountOne = () => countOne * 2;

  return (
    <>
      <h1>Counter</h1>
      <p>Count One:{countOne}</p>
      <button onClick={incrementOne}>+</button>
      <p>Count Two:{countTwo}</p>
      <button onClick={incrementTwo}>+</button>
      <Count doubleCountOne={doubleCountOne} />
    </>
  );
}

export default App;

Countコンポーネントはmemoでラップしています。


import { memo } from 'react';

const Count = memo((props) => {
  const { doubleCountOne } = props;
  return <div>Double Count One: {doubleCountOne}</div>;
});

export default Count;

カスタムフックuseResizeHook

useEffect+EventListenerのコードをカスタムフックに変更します。


import { useEffect, useState } from 'react';

export function useResizeHook() {
  const [windowSize, setWindowSize] = useState({
    innerWidth: undefined,
    innerHeight: undefined,
  });

  useEffect(() => {
    function handleResize() {
      setWindowSize({
        innerWidth: window.innerWidth,
        innerHeight: window.innerHeight,
      });
    }

    handleResize();
    window.addEventListener('resize', handleResize);

    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return windowSize;
}

作成したカスタムフックをimportして利用します。


import { useResizeHook } from './hooks/useResizeHook';

function App() {
  const windowSize = useResizeHook();

  return (
    <>
      <h1>コンテンツ領域のサイズ</h1>
      <p>フラウザのコンテンツ領域の幅: {windowSize.innerWidth}px</p>
      <p>フラウザのコンテンツ領域の高さ: {windowSize.innerHeight}px</p>
    </>
  );
}

export default App;

Form

useStateを利用した場合


import { useState } from 'react';

function App() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log(`emai:${email}, password:${password}`);
  };

  const handleChangeEmail = (e) => {
    setEmail(e.target.value);
  };
  const handleChangePassword = (e) => {
    setPassword(e.target.value);
  };
  return (
    <div className="App">
      <h1>ログイン</h1>
      <form onSubmit={handleSubmit}>
        <div>
          <label htmlFor="email">Email</label>
          <input id="email" value={email} onChange={handleChangeEmail} />
        </div>
        <div>
          <label htmlFor="password">パスワード</label>
          <input
            id="password"
            value={password}
            onChange={handleChangePassword}
            type="password"
          />
        </div>
        <div>
          <button type="submit">ログイン</button>
        </div>
      </form>
    </div>
  );
}

export default App;

useRefを利用した場合


import { useRef } from 'react';

function App() {
  const emailRef = useRef(null);
  const passwordRef = useRef(null);

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log(
      `emai:${emailRef.current.value}, password:${passwordRef.current.value}`
    );
  };

  return (
    <div className="App">
      <h1>ログイン</h1>
      <form onSubmit={handleSubmit}>
        <div>
          <label htmlFor="email">Email</label>
          <input id="email" ref={emailRef} />
        </div>
        <div>
          <label htmlFor="password">パスワード</label>
          <input id="password" ref={passwordRef} type="password" />
        </div>
        <div>
          <button type="submit">ログイン</button>
        </div>
      </form>
    </div>
  );
}

export default App;

select


function App() {
  const tasks = [
    {
      id: 1,
      title: 'Call Client',
      complete: false,
    },
    {
      id: 2,
      title: 'Workout',
      complete: false,
    },
    {
      id: 3,
      title: 'Buy Snack',
      compolete: true,
    },
  ];

  const UnCompleteTasks = tasks.filter((task) => task.complete === false);

  return (
    <>
      <h1>UnComplete Tasks</h1>
      <ul>
        {UnCompleteTasks.map((task) => (
          <li key={task.id}>{task.title}</li>
        ))}
      </ul>
    </>
  );
}

export default App;

import { useState } from 'react';

function App() {
  const [selectedValue, setSelectedValue] = useState('Joe');

  const handleChange = (e) => {
    console.log(e.target.value);
    setSelectedValue(e.target.value);
  };
  return (
    <>
      <h1>select</h1>
      <select value={selectedValue} onChange={handleChange}>
        <option value="John">John</option>
        <option value="Joe">Joe</option>
        <option value="Kevin">Kevin</option>
      </select>
    </>
  );
}

export default App;

select+map関数


import { useState } from 'react';

function App() {
  const users = ['John', 'Joe', 'Kevin', 'Jane', 'Franc'];
  const [selectedValue, setSelectedValue] = useState('Joe');

  const handleChange = (e) => {
    console.log(e.target.value);
    setSelectedValue(e.target.value);
  };
  return (
    <>
      <h1>select</h1>
      <select value={selectedValue} onChange={handleChange}>
        {users.map((user) => (
          <option key={user} value={user}>
            {user}
          </option>
        ))}
      </select>
    </>
  );
}

export default App;