クイックスタート

React ドキュメントへようこそ! このページでは、日々の開発で使用する React のコンセプトのうち 80% の部分を紹介します。

このページで学ぶこと

  • コンポーネントの作成とネスト
  • マークアップとスタイルの追加
  • データの表示
  • 条件分岐とリストのレンダー
  • イベントへの応答と画面の更新
  • コンポーネント間でのデータの共有

コンポーネントの作成とネスト

React アプリはコンポーネントで構成されています。コンポーネントとは、独自のロジックと外見を持つ UI(ユーザインターフェース)の部品のことです。コンポーネントは、ボタンのような小さなものである場合も、ページ全体を表す大きなものである場合もあります。

React におけるコンポーネントとは、マークアップを返す JavaScript 関数です。

function MyButton() {
return (
<button>I'm a button</button>
);
}

MyButton を宣言したら、別のコンポーネントにネストできます。

export default function MyApp() {
return (
<div>
<h1>Welcome to my app</h1>
<MyButton />
</div>
);
}

<MyButton /> が大文字で始まっていることに注意してください。こうすることで、React のコンポーネントであるということを示しています。React のコンポーネント名は常に大文字で始める必要があり、HTML タグは小文字でなければなりません。

結果を見てみましょう。

function MyButton() {
  return (
    <button>
      I'm a button
    </button>
  );
}

export default function MyApp() {
  return (
    <div>
      <h1>Welcome to my app</h1>
      <MyButton />
    </div>
  );
}

export default キーワードは、ファイル内のメインコンポーネントを指定しています。このような JavaScript の構文に関して分からない部分があれば、MDNjavascript.info に素晴らしいリファレンスがあります。

JSX でマークアップを書く

上で見たマークアップ構文は、JSX と呼ばれるものです。使用は任意ですが、その便利さゆえにほとんどの React プロジェクトでは JSX が使用されています。ローカル開発におすすめのツールは、すべて JSX に対応しています。

JSX は HTML より構文が厳格です。<br /> のようにタグは閉じる必要があります。また、コンポーネントは複数の JSX タグを return することはできません。<div>...</div> や空の <>...</> ラッパのような共通の親要素で囲む必要があります。

function AboutPage() {
return (
<>
<h1>About</h1>
<p>Hello there.<br />How do you do?</p>
</>
);
}

JSX に変換しないといけない HTML がたくさんある場合は、オンラインコンバータを使うことができます。

スタイルの追加

React では、CSS クラスを className で指定します。HTML の class 属性と同じ方法で動作します。

<img className="avatar" />

そして、別の CSS ファイルに対応する CSS ルールを記述します:

/* In your CSS */
.avatar {
border-radius: 50%;
}

React には CSS ファイルの追加方法に関する規則はありません。最も単純なケースでは、HTML に <link> タグを追加します。ビルドツールやフレームワークを使っている場合は、そちらのドキュメントを参照して、プロジェクトに CSS ファイルを追加する方法を確認してください。

データの表示

JSX を使うことで、JavaScript 内にマークアップを入れることができます。波括弧を使うことで、逆に JSX の中から JavaScript に「戻る」ことができ、コード内の変数を埋め込んでユーザに表示することができます。たとえば、以下は user.name を表示します:

return (
<h1>
{user.name}
</h1>
);

JSX の属性 (attribute) の部分から JavaScript に「戻る」こともでき、その場合引用符の代わりに波括弧を使う必要があります。例えば、className="avatar" は CSS クラスとして "avatar" 文字列を渡すものですが、src={user.imageUrl} は JavaScript の user.imageUrl 変数の値を読み込み、その値を src 属性として渡します:

return (
<img
className="avatar"
src={user.imageUrl}
/>
);

JSX の波括弧の中にもっと複雑な式を入れることもできます。例えば、文字列の連結ができます:

const user = {
  name: 'Hedy Lamarr',
  imageUrl: 'https://i.imgur.com/yXOvdOSs.jpg',
  imageSize: 90,
};

export default function Profile() {
  return (
    <>
      <h1>{user.name}</h1>
      <img
        className="avatar"
        src={user.imageUrl}
        alt={'Photo of ' + user.name}
        style={{
          width: user.imageSize,
          height: user.imageSize
        }}
      />
    </>
  );
}

上記の例では、style={{}} は特別な構文ではなく、style={ } という JSX の波括弧内にある通常の {} オブジェクトです。スタイルが JavaScript 変数に依存する場合は、style 属性を使うことができます。

条件付きレンダー

React には、条件分岐を書くための特別な構文は存在しません。代わりに、通常の JavaScript コードを書くときに使うのと同じ手法を使います。例えば、if ステートメントを使って条件付きで JSX を含めることができます:

let content;
if (isLoggedIn) {
content = <AdminPanel />;
} else {
content = <LoginForm />;
}
return (
<div>
{content}
</div>
);

コンパクトなコードをお望みの場合は、条件 ? 演算子を使用できます。if とは異なり、JSX の中で動作します。

<div>
{isLoggedIn ? (
<AdminPanel />
) : (
<LoginForm />
)}
</div>

else 側の分岐が不要な場合は、短い論理 && 構文を使用することもできます。

<div>
{isLoggedIn && <AdminPanel />}
</div>

これらのアプローチはすべて、属性を条件付きで指定する場合にも機能します。このような JavaScript 構文の一部に慣れていないという場合、最初は常に if...else を使用することにしても構いません。

リストのレンダー

コンポーネントのリストをレンダーする場合は、for ループ配列の map() 関数 といった JavaScript の機能を使って行います。

例えばこのような商品の配列があるとします:

const products = [
{ title: 'Cabbage', id: 1 },
{ title: 'Garlic', id: 2 },
{ title: 'Apple', id: 3 },
];

コンポーネント内で、map() 関数を使って商品の配列を <li> 要素の配列に変換します:

const listItems = products.map(product =>
<li key={product.id}>
{product.title}
</li>
);

return (
<ul>{listItems}</ul>
);

<li>key 属性があることに注意してください。リスト内の各項目には、兄弟の中でそれを一意に識別するための文字列または数値を渡す必要があります。通常、key はデータから来るはずで、データベース上の ID などが該当します。React は、後でアイテムを挿入、削除、並べ替えることがあった際に、何が起こったかを key を使って把握します。

const products = [
  { title: 'Cabbage', isFruit: false, id: 1 },
  { title: 'Garlic', isFruit: false, id: 2 },
  { title: 'Apple', isFruit: true, id: 3 },
];

export default function ShoppingList() {
  const listItems = products.map(product =>
    <li
      key={product.id}
      style={{
        color: product.isFruit ? 'magenta' : 'darkgreen'
      }}
    >
      {product.title}
    </li>
  );

  return (
    <ul>{listItems}</ul>
  );
}

イベントに応答する

コンポーネントの中でイベントハンドラ関数を宣言することで、イベントに応答できます:

function MyButton() {
function handleClick() {
alert('You clicked me!');
}

return (
<button onClick={handleClick}>
Click me
</button>
);
}

onClick={handleClick} の末尾に括弧がないことに注意してください! そこでイベントハンドラ関数を呼び出すわけではありません。渡すだけです。ユーザがボタンをクリックしたときに、React がイベントハンドラを呼び出します。

画面の更新

しばしば、コンポーネントに情報を「記憶」させて表示したいことがあります。例えば、ボタンがクリックされた回数を数えて覚えておきたい場合です。これを行うには、コンポーネントに state を追加します。

まず、React から useState をインポートします。

import { useState } from 'react';

これで、コンポーネント内に state 変数を宣言できます:

function MyButton() {
const [count, setCount] = useState(0);
// ...

useState からは 2 つのものが得られます。現在の state (count) と、それを更新するための関数 (setCount) です。名前は何でも構いませんが、慣習的には [something, setSomething] のように記述します。

ボタンが初めて表示されるとき、count0 になります。これは useState()0 を渡したからです。state を変更したいときは、setCount() を呼び出し、新しい値を渡します。このボタンをクリックすると、カウンタが増加します:

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

function handleClick() {
setCount(count + 1);
}

return (
<button onClick={handleClick}>
Clicked {count} times
</button>
);
}

React は、再度コンポーネントの関数を呼び出します。今度は count1 になっています。次の呼び出しでは 2 になっています。次々と増えていきます。

同じコンポーネントを複数の場所でレンダーした場合、それぞれが独自の state を持ちます。それぞれのボタンを個別にクリックしてみてください:

import { useState } from 'react';

export default function MyApp() {
  return (
    <div>
      <h1>Counters that update separately</h1>
      <MyButton />
      <MyButton />
    </div>
  );
}

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

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <button onClick={handleClick}>
      Clicked {count} times
    </button>
  );
}

各ボタンがそれぞれ count という state を「記憶」し、他のボタンに影響を与えないことに注意してください。

フックの使用

use で始まる関数は、フック (Hook) と呼ばれます。useState は React が提供する組み込みのフックです。API リファレンスで他の組み込みフックを見ることができます。また、既存のフックを組み合わせて独自のフックを作成することもできます。

フックには通常の関数より多くの制限があります。フックはコンポーネントのトップレベル(または他のフック内)でのみ呼び出すことができます。条件分岐やループの中で useState を使いたい場合は、新しいコンポーネントを抽出してそこに配置します。

コンポーネント間でデータを共有する

前述の例では、それぞれの MyButton が独立した count を持っており、ボタンがクリックされるたびにクリックされたボタンの count だけが変更されました。

MyApp という名前の親コンポーネントと MyButton という名前の 2 つの子コンポーネントを持つツリーを示す図。どちらの MyButton コンポーネントも、カウントの値は 0。
MyApp という名前の親コンポーネントと MyButton という名前の 2 つの子コンポーネントを持つツリーを示す図。どちらの MyButton コンポーネントも、カウントの値は 0。

最初、それぞれの MyButtoncount0

前の図と同じだが、1 番目の MyButton コンポーネントのカウントがクリックされ、カウント値が 1 に増えている。2 番目の MyButton コンポーネントの値は 0 のまま。
前の図と同じだが、1 番目の MyButton コンポーネントのカウントがクリックされ、カウント値が 1 に増えている。2 番目の MyButton コンポーネントの値は 0 のまま。

1 番目の MyButtoncount1 に更新

ただし、コンポーネント間でデータを共有し、常に一緒に更新したいということもよくあります。

両方の MyButton コンポーネントが同じ count を表示し、一緒に更新されるようにするには、状態を個々のボタンから「上に」移動して、それらすべてを含む最も近いコンポーネントに入れます。

この例では、MyApp がそれです:

MyApp という名前の親コンポーネントと、MyButton という名前の 2 つの子コンポーネントを持つツリーを示す図。MyApp には値が 0 のカウントが含まれ、それが両方の MyButton コンポーネントに渡される。値は 0。
MyApp という名前の親コンポーネントと、MyButton という名前の 2 つの子コンポーネントを持つツリーを示す図。MyApp には値が 0 のカウントが含まれ、それが両方の MyButton コンポーネントに渡される。値は 0。

最初、MyAppcount0 で、どちらの子もそれを受け取っている。

前の図と同じだが、親 MyApp コンポーネントのカウントがクリックによりハイライトされ、値が 1 になっている。子 MyButton コンポーネントも両方ハイライトされ、それぞれの子のカウント値が 1 になっている。値が下に渡されたことを示している。
前の図と同じだが、親 MyApp コンポーネントのカウントがクリックによりハイライトされ、値が 1 になっている。子 MyButton コンポーネントも両方ハイライトされ、それぞれの子のカウント値が 1 になっている。値が下に渡されたことを示している。

クリック時に MyAppcount1 に更新し、それが両方の子に渡される

こうすれば、どちらのボタンをクリックしても、MyAppcount が更新され、連動して MyButton の両方のカウントが更新されるでしょう。以下は、コードでこれを表現する方法です。

まず、MyButton から MyApp に、state の移動を行います。

export default function MyApp() {
const [count, setCount] = useState(0);

function handleClick() {
setCount(count + 1);
}

return (
<div>
<h1>Counters that update separately</h1>
<MyButton />
<MyButton />
</div>
);
}

function MyButton() {
// ... we're moving code from here ...
}

次に、MyApp から各 MyButtonstate を渡し、共有のクリックハンドラも一緒に渡します。以前に <img> のような組み込みタグで行ったときと同様、JSX の波括弧を使うことで MyButton に情報を渡すことができます。

export default function MyApp() {
const [count, setCount] = useState(0);

function handleClick() {
setCount(count + 1);
}

return (
<div>
<h1>Counters that update together</h1>
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
</div>
);
}

このように渡される情報は props と呼ばれます。MyApp コンポーネントは count 状態と handleClick イベントハンドラを保持しており、それらをどちらも props として各ボタンに渡します。

最後に、MyButton を変更して、親コンポーネントから渡された props を読み込むようにします。

function MyButton({ count, onClick }) {
return (
<button onClick={onClick}>
Clicked {count} times
</button>
);
}

ボタンをクリックすると、onClick ハンドラが発火します。各ボタンの onClick プロパティは MyApp 内の handleClick 関数となっているので、その中のコードが実行されます。そのコードは setCount(count + 1) を呼び出し、count という state 変数をインクリメントします。新しい count の値が各ボタンに props として渡されるため、すべてのボタンに新しい値が表示されます。この手法は「state のリフトアップ(持ち上げ)」と呼ばれています。リフトアップすることで、state をコンポーネント間で共有できました。

import { useState } from 'react';

export default function MyApp() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <div>
      <h1>Counters that update together</h1>
      <MyButton count={count} onClick={handleClick} />
      <MyButton count={count} onClick={handleClick} />
    </div>
  );
}

function MyButton({ count, onClick }) {
  return (
    <button onClick={onClick}>
      Clicked {count} times
    </button>
  );
}

次のステップ

これで、React のコードを書く基本が分かったことになります!

チュートリアルをチェックして、これらの概念を実践し、React を使った最初のミニアプリを作成しましょう。