Skip to the content.

Reactの基本動作

目次

Reactを動かしてみる

以下のhtmlファイルを作成して、reactを動かしてみましょう。ここでの記述方法は、通常の開発で使うことはありませんので、覚える必要はありません。ここでは、Reactがどのような手順でhtmlに変更を加えているのかを確認してください。好きなディレクトリに以下のindex.htmlを作成してください。

index.html

<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
    <div id="app"></div>
    <script>
        const appElement = document.querySelector('#app');
        const root = ReactDOM.createRoot(appElement);
        root.render("Hello React");
    </script>
</body>
</html>

作成したindex.htmlをWebブラウザで開いてください。「Hello React」の文字が表示されれば成功です。

headタグ内では、Reactを動かすためのライブラリを読み込んでいます。

bodyタグ内に記述したscriptによって、<div id="app"></div>の中に、root.renderの引数が挿入されます。 root.renderの引数を色々変えてみましょう。

Reactの記法(JSX)

Reactでは、HTMLタグ(に似たもの)をjavascriptに直接記述する特殊な記法を使います。一般的にこの記法は、JSXと呼ばれています。 先ほどのhtmlをJSXの記法を使って書き換えてみましょう。

sample.htmlbodyタグ

<body>
    <div id="app"></div>
    <script>
        const appElement = document.querySelector('#app');
        const root = ReactDOM.createRoot(appElement);
        root.render(<h1>Hello</h1>);
    </script>
</body>

このように変更すると、エラーが発生していることが分かります。これは、通常のjavascriptでは、<h1>Hello React</h1>のようなhtmlタグのような記述ができないためです。

Reactでは、babelというライブラリが、Reactのコードをjavascriptに変換するようになっています。babelがReactのコードを変換してくれるように、sample.htmlを以下のように編集しましょう。

sample.htmlbodyタグ

<body>
    <div id="app"></div>
    <script type="text/babel">
        const appElement = document.querySelector('#app');
        const root = ReactDOM.createRoot(appElement);
        root.render(<h1>Hello React</h1>);
    </script>
</body>

これで、正しく動作するはずです。

Reactのコンセプト

Reactでは、コンポーネントと呼ばれる単位で、コードを記述していきます。コンポーネントとは、画面の各構成要素をReactで定義したものです。 これによって、コードが整理され、使い回しができ、疎結合になります。

それでは、先ほどのhtmlを編集して、コンポーネントを定義していきましょう。

sample.htmlbodyタグ

<body>
    <div id="app"></div>
    <script type="text/babel">
        const appElement = document.querySelector('#app');
        const root = ReactDOM.createRoot(appElement);

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

        root.render(<Hello />);
    </script>
</body>

コンポーネントは、以下のように関数で定義し、必ず最初の文字を大文字で定義します。

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

※コンポーネントをクラスで記述するものもありますが、これは以前のReactの記法です。すごく特殊な場合を除いては、関数でコンポーネントを定義しましょう。

Reactアプリ開発の始め方 (vite)

ここから本格的にReactのプロジェクトを作っていきましょう。reactのプロジェクトは、viteを利用することで、簡単に始めることができます。 以下ようなコマンドで、Reactのtemplateを生成することができます。(node.jsをインストールする必要があります。)

npm create vite@latest

コマンド実行後、いくつか質問されるので、それに答えていきます。

まず、project名を設定します。 デフォルトは、vite-projectとなっています。

? Project name: > vite-project

次に、どのフレームワークを利用するか答えます。 ここでは、Reactを選択しましょう。

? Select a framework: › - Use arrow-keys. Return to submit.
❯   Vanilla
    Vue
    React
    Preact
    Lit
    Svelte
    Solid
    Qwik
    Others

次に、TypescriptかJavascriptを選択します。SWCは、高速なコンパイラです。特に理由がなければ、+ SWCの方を選択してください。

ここでは、Typescriptで解説をしていくので、TypeScript + SWCを選択してください。

? Select a variant: › - Use arrow-keys. Return to submit.
❯   TypeScript
    TypeScript + SWC
    JavaScript
    JavaScript + SWC

これで、テンプレートが作成されます。ただライブラリ等はインストールされていない状態なので、以下のコマンドでインストールをしていきます。

cd {プロジェクト名}
npm install

インストール終了したら、プロジェクトディレクトリ配下の構成は、以下のようになっているはずです。

.
├── README.md
├── index.html
├── package.json
├── public
├── src
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts

開発サーバを立ち上げてみましょう。開発サーバの立ち上げは、以下のコマンドです。

npm run dev

デフォルトでは、http://localhost:5173/がブラウザで開かれ、画面を見ることができます。以下のような画面が表示されれば、成功です。

create vite default

それでは、ファイルの中身を見ていきましょう。プロジェクトディレクトリ直下にあるindex.htmlを開いてみてください。以下のような内容になっているはずです。

index.html

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + React + TS</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

これが、ベースとなるhtmlファイルです。bodyタグにある<div id="root"></div>の中は、Reactで構成していく部分になります。

headタグ内は、必要に応じて変更してください。特に<html lang="en">の部分は、開発している画面の言語に合うように設定を変えてください。日本語の場合は、<html lang="ja">です。 また、アイコンなどもviteのものになっているので、変更するようにしてください。

次にsrcディレクトリの中を見てみましょう。ここには、ソースコードが格納されています。通常、typescriptのソースコードの拡張子は、.tsですが、Reactでは、上で紹介したJSXという記法を使うため、コンポーネントを記述する場合は、拡張子も変わり、.tsxとなります。(javascriptの場合は、.jsx)

src/main.tsxを開いてみてください。

src/main.tsx

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
);

ここの内容は、HTMLに直接記述したものと同じような内容であることが分かると思います。 このスクリプトによって、index.html<div id="root"></div>の中に、root.renderの引数が挿入されます。 root.renderの引数であるReact.StrictMode, Appは、コンポーネントになります。React.StrictModeは、開発時にバグを見つけやすくするようにするもので、画面は何も変わりませんが、プログラムの挙動が変わります。

React.StrictModeによって以下のような挙動が追加されます。(参考:StrictMode - React

次は、Appコンポーネントについてみてみましょう。src/App.tsxを開いてください。

src/App.tsx

import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'

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

  return (
    <>
      <div>
        <a href="https://vitejs.dev" target="_blank">
          <img src={viteLogo} className="logo" alt="Vite logo" />
        </a>
        <a href="https://react.dev" target="_blank">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <h1>Vite + React</h1>
      <div className="card">
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
        <p>
          Edit <code>src/App.tsx</code> and save to test HMR
        </p>
      </div>
      <p className="read-the-docs">
        Click on the Vite and React logos to learn more
      </p>
    </>
  )
}

export default App;

ここには、実際にブラウザの画面上に表示されているものが定義されていることが分かると思います。後の章で説明しますが、useStateを使った状態管理も行なっています。

それでは、このApp.tsxをもっと単純なものに書き換えてみましょう。

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

export default App;

これで、HTMLに直接記述したときと同じ内容になっているはずです。ブラウザ画面を見てみてください。 npm run devを終了させた人は、npm run devを実行して、http://localhost:5173/をブラウザで開いてください。

以下のような画面になっていれば、成功です。

Hello React

コンポーネントの作成

それでは、コンポーネントを作成してみましょう。

コンポーネントを定義する際には、基本的に以下のルールがあります。

1つのファイルにつき、1つのコンポーネントというルールは慣習的で、実際に1つのファイルに複数のコンポーネントを定義しても、エラーにはなりません。 ディレクトリ構成は様々ありますが、1つのファイルに1つのコンポーネントというルールは、守られていることが多いようです。

ここでは、とりあえずcomponentsというディレクトリを作成し、その配下にコンポーネントを定義したファイルを配置していきましょう。 それでは、以下のディレクトリ、ファイルを作成し、Helloコンポーネントを作成していきましょう。

srcディレクトリ配下に、componentsディレクトリを作成し、その中にHello.tsxを作成してください。 Helloコンポーネントを作成するので、Hello.tsxというファイル名になります。

.
└── src
    └──components
        └── Hello.tsx

Hello.tsx

const Hello: React.FC = () => {
    return <h1>Hello React</h1>
};

export default Hello;

それでは、作成したHelloコンポーネントを使って、App.tsxを書き換えましょう。

App.tsx

import Hello from "./components/Hello";

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

export default App;

ブラウザ画面を確認してみましょう。npm run devを終了させた人は、npm run devを実行して、http://localhost:5173/をブラウザで開いてください。 プログラムの記述は変わりましたが、表示されている内容は変わっていないはずです。

コンポーネント間の値の受け渡し(props)

Reactはコンポーネントという単位で、細かくコードを分けていくので、コンポーネント間で値を共有したい場合がよくあります。(今はまだかもしれませんが) コンポーネント間での値の受け渡しには、propsを使います。このpropsは、コンポーネント関数の引数となる部分で、必ずjavascriptのオブジェクトになります。

それでは、Appコンポーネントから、Helloコンポーネントにstringを渡してみましょう。

まず、値を渡す側Appは、以下のように記述します。

function App() {
  return (
    <Hello target="React"/>
  );
}

このようにすると、Helloコンポーネントに以下のようなオブジェクトが渡されます。

{ target: "React" }

それでは、Helloコンポーネントでは、どのように値が渡されているか確認しましょう。 Helloコンポーネントの中身を以下のように変更してください。

interface HelloProps {
  target: string;
}

const Hello: React.FC<HelloProps> = (props) => {
  console.log(props)
  return <h1>Hello React</h1>
};

Chromeの検証ツールからコンソールの出力を確認してみましょう。

それでは、propsで渡された値を使ってみましょう。javascriptの分割代入を使うことで、propsの中身を受け取ります。

const Hello: React.FC<HelloProps> = ({ target }) => {
  return <h1>Hello {target}</h1>;
};

ここで、<h1>タグ内をみてください。変数targetは、{target}として渡しています。単にtargetとしてしまうと、文字列のtargetと認識されてしまいます。そのため、JSX記法で、HTMLタグ内やコンポーネント内で変数やオブジェクトを使う場合、{}をつけましょう。

propsの特殊な例(children)

propsで渡す値の中でchildrenは、渡し方が異なります。このchildrenは、<h1>Hello React</h1>で言うとHello Reactの部分になります。この例では、HTMLタグでしたが、コンポーネントでも同じように値を渡すことができます。

また、childrenは文字列だけでなく、HTML要素やコンポーネントを渡すことができます。

それでは、Helloコンポーネントがchildrenを受け取るように改造しましょう。

Hello.tsx

interface HelloProps {
  target: string;
  children: React.ReactNode;
}

const Hello: React.FC<HelloProps> = ({ target, children }) => {
  return (
    <div>
      <h1>Hello {target}</h1>
      {children}
    </div>
  );
};

export default Hello;

次にHelloコンポーネントを使っているApp.tsxも修正しましょう。

App.tsx

function App() {
  return <Hello target="React">Hi</Hello>;
}

それでは、ブラウザ画面を開いてください。npm run devを終了させた人は、npm run devを実行して、http://localhost:5173/をブラウザで開いてください。

以下のような画面が表示されれば、成功です。

Hello React Hi

このchildrenには、今回のように文字列は、もちろんですが、HTML要素、コンポーネントも渡すことができます。以下のように色々変更してみてください。

function App() {
  return (
    <Hello target="React">
      <button>Hi</button>
    </Hello>
  );
}

特殊なコンポーネントReact.Fragment

Reactコンポーネントには、必ず1つの要素を返すというルールがあります。(複数の要素を変えることはできない)

例えば、以下のように複数のHTML要素を変えそうとすると、エラーになることが分かります。

const Hello = () => {
  return <div>Hello</div><div>React</div>;
};

ただ、状況によっては、複数の要素を返すようなコンポーネントを作りたいことがあります。その時に利用するのがReact.Fragmentです。React.Fragmentは、以下のコードに示すように<>...</>という構文で表せます。

const Hello = () => {
  return (
    <>
      <div>Hello</div>
      <div>React</div>
    </>
  );
};

このReact.Fragmentは、React上では、一つの要素(コンポーネント)と解釈されますが、Reactが最終的に生成するHTMLでは、React.Fragmentは消えた状態になります。

コンポーネントの表示に配列を使う場合の注意点

Reactでは、以下のように配列を使って、コンポーネントやHTML要素を複数表示させることができます。以下のAppコンポーネントでは、配列["A", "B", "C"]を使って、<div>A</div>, <div>B</div>, <div>C</div>を生成しています。

function App() {
  const sampleList = ["A", "B", "C"];
  return (
    <>
      {sampleList.map((value) => {
        return <div>{value}</div>;
      })}
    </>
  );
}

この配列を使った表示をやることに問題はありませんし、むしろ活用してください。ただし、一点だけ注意することがあります。

実際にこのコードを書いてブラウザで実行結果を確認してみるとわかるのですが、コンソールを見てみると以下のような警告が出ているかと思います。

Warning: Each child in a list should have a unique “key” prop.

これは、リストから生成させたHTML要素(またはコンポーネント)にkeypropにユニークな値を設定してくださいという警告です。以下のように変更する必要があります。

function App() {
  const sampleList = ["A", "B", "C"];
  return (
    <>
      {sampleList.map((value) => {
        // key propにvalueを設定
        return <div key={value}>{value}</div>;
      })}
    </>
  );
}

このkeyが必要な理由は、ReactがDOMの差分を検知してレンダリングを行う際に、配列で生成された部分は、keyを元に対応づけを行い、差分を確認しています。そのため、keyを正しく設定していないと、レンダリングが不正確になってしまいます。

このkeyに設定する値として、配列のindexを指定することも考えられますが、これはNGです。例えば、配列の並び替えが行われた時も、<div>A</div>を生成した時は、並び替えが発生する前に<div>A</div>を生成した時と同じkeyである必要があるためです。

// NGな例
function App() {
  const sampleList = ["A", "B", "C"];
  return (
    <>
      {sampleList.map((value, index) => {
        // key propにindexを設定するのはNG!!
        return <div key={index}>{value}</div>;
      })}
    </>
  );
}

Appendix A : key propを正しく設定しなかった時に発生する問題で、key propに配列のindexを設定したときの不正確な挙動の例に付いて説明しています。

Next: Chapter3 スタイリング

Prev: Chapter1 Reactの開発環境の準備