rikuto tech blog

ゆる〜くやってます

React Tutorialを TypeScriptとHooksで書き直してみた①

概要

前回記事で書いた「りあクト!」を読んで学んだことですが、現在のReactでは関数コンポーネントが主流になっており、公式チュートリアルでメインに扱われているクラスコンポーネントはあまり用いられないようです。 また、実践的な開発では、JavaScriptよりもTypeScriptが主に使われています。

そこで、ReactチュートリアルをTypeScript、関数コンポーネント、Hooksで書き直してみました。 流れは公式チュートリアルのままになっています。

※とはいえ、stateを理解するにはクラスコンポーネントを理解しておくと良さそうなので、いきなりHooksを使うより、一度公式チュートリアルをやってよかったかなと思います。

私がトライしたときに作ったコードはこちらです↓

github.com

主な環境

  • macOS 11.4
  • node 14.4.0
  • TypeScript 4.3.2
  • React 17.0.2

チュートリアルの準備

基本的にはこの公式チュートリアルの流れに従って準備します。

手順

  1. npx create-react-app my-app --template=typescript でプロジェクトを作成
  2. 作成されたmy-app/src/配下のファイルを全部消す
  3. src配下に、index.tsxを作成し、このコードをコピペ
  4. 同じくindex.cssを作成し、このコードをコピペ

スターターコードの中身

このindex.tsxは、公式チュートリアルのスターターコードindex.jsを関数コンポーネントとTSで書き直したものです。

import { VFC } from 'react';
import ReactDOM from 'react-dom';
import './index.css';

const Square: VFC = () => (
  <button type="button" className="square">
    {/* TODO */}
  </button>
);

const Board: VFC = () => {
  const renderSquare: VFC = () => <Square />;

  const status = 'Next player: X';

  return (
    <div>
      <div className="status">{status}</div>
      <div className="board-row">
        {renderSquare(0)}
        {renderSquare(1)}
        {renderSquare(2)}
      </div>
      <div className="board-row">
        {renderSquare(3)}
        {renderSquare(4)}
        {renderSquare(5)}
      </div>
      <div className="board-row">
        {renderSquare(6)}
        {renderSquare(7)}
        {renderSquare(8)}
      </div>
    </div>
  );
};

const Game: VFC = () => (
  <div className="game">
    <div className="game-board">
      <Board />
    </div>
    <div className="game-info">
      <div>{/* status */}</div>
      <ol>{/* TODO */}</ol>
    </div>
  </div>
);

// ========================================

ReactDOM.render(<Game />, document.getElementById('root'));

各関数コンポーネントにくっついてるVFCは、関数コンポーネントの型を表します。

具体的にはpropsを引数にとり、ReactElementもしくはnullを返す関数として定義されているオブジェクトです。

VoidFunctionComponentエイリアスになっていて、VFCと表現できます。

参考
(Reactの関数コンポーネントの型には、元々FunctionComponent型があったようですが、現在推奨されていないようです。「りあクト!」にも同様の説明がありました。こちらの記事がわかりやすかったです)

個人的に気になったこと

JS/TSには関数閉包(クロージャ)という概念が存在し、関数の中に関数を定義することができます。 (正確には、関数の中に関数を定義できるから、関数閉包ができると言ったほうがいいかもしれません)

C++Pythonを主に扱ってきた私としては、なかなか奇妙な感じがします。
このコードでも、次の箇所に使っています。

const Board: VFC = () => {
  const renderSquare: VFC = () => <Square />;

関数閉包については、こちらのページがわかりやすかったです。

余計な説明が多くなりましたが、次回からこのコードをチュートリアルに従って三目並べを作っていきます!