クイックスタート
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 の構文に関して分からない部分があれば、MDN や javascript.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]
のように記述します。
ボタンが初めて表示されるとき、count
は 0
になります。これは 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 は、再度コンポーネントの関数を呼び出します。今度は count
が 1
になっています。次の呼び出しでは 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
だけが変更されました。
ただし、コンポーネント間でデータを共有し、常に一緒に更新したいということもよくあります。
両方の MyButton
コンポーネントが同じ count
を表示し、一緒に更新されるようにするには、状態を個々のボタンから「上に」移動して、それらすべてを含む最も近いコンポーネントに入れます。
この例では、MyApp
がそれです:
こうすれば、どちらのボタンをクリックしても、MyApp
の count
が更新され、連動して 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
から各 MyButton
に state を渡し、共有のクリックハンドラも一緒に渡します。以前に <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> ); }