「劇場版「鬼滅の刃」 無限列車編」の煉獄さんの姿にいつも泣きそうになるオウルです。ついにBlu-ray&DVDが発売されましたね。妻から父の日にプレゼントしてもらってからは何度も見てます。ただ僕以上に娘がよく見てますけど。
Reactには以前から興味はあって、本業で使う機会があればと思っていましたが、当面そういう機会もなさそうなので、Rust同様、プライベートで学習していきます。
Reactの公式ドキュメントは、とても洗礼されてると思うのでチュートリアル:React の導入をまずは挑戦です。せっかくなので最新情報を追いながら、Typescriptに置き換えていきます。また、後で復習しやすいように、参考にしたドキュメントのリンクを貼っていきます。
language | React v17.0 |
os | WSL Ubuntu 21.04 |
editor | VSCode |
Reactチュートリアル
では、チュートリアル:React の導入を進めていきます。
チュートリアルの前提知識にも記載がありますが、ある程度JavaScriptの知識が前提となっています。JavaScriptを復習したい人や、はじめての人は紹介されているガイドから始める方が、Reactチュートリアルを早く理解できると思います。後、おまけで過去のJacascriptについて記事も紹介しておきます。
Create React App
Create React App は React を学習するのに快適な環境であり、React で新しいシングルページアプリケーションを作成するのに最も良い方法です。
とありますので、Create React Appを使用していきます。内部ではBabelとwebpackを利用しているとのことですが、チュートリアルに関して言えば、この辺りは意識する必要なくTypescriptで実装していけます。因みにBabelとwebpackとTypescriptの環境構築には、以下の記事で説明していますが、この辺りをまるっとCreate React Appがいいようにしてくれる感じです。
ステートフックの利用法
Reactチュートリアルを読み進めると、はじめにクラスコンポーネントで記述されていた箇所を関数コンポーネントに書き換える流れになっています。ですが、React 16.8 で追加された新機能のhookの補足がありません。なので、ステートフックの利用法を参考に関数コンポーネントを実装していきます。
このhookにはルールがあり、詳細はフックのルールに記載されています。Create React Appでは、デフォルトで自動的に、このルールを強制するためのlinter プラグインが含まれているみたいです。
三目並べゲーム
React.FunctionComponent(React.FC)とReact.VoidFunctionComponent(React.VFC)について色々意見があるようですが、初心者の僕としては、React TypeScript CheatsheetのFunction Componentsを参考に実装していきます。
Squareコンポーネント
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/** * Squareコンポーネントのpropsを型エイリアスで定義 * Indexed Access Types: https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html * VoidFunction: https://microsoft.github.io/PowerBI-JavaScript/interfaces/_node_modules_typedoc_node_modules_typescript_lib_lib_dom_d_.voidfunction.html */ type SquareProps = { onClick: VoidFunction, // or onClick: () => void value: SquareValue, }; type SquareValue = 'X' | 'O' | null; /** * Squareコンポーネント * @param props * @returns */ const Square = (props: SquareProps) => { return ( <button className="square" onClick={() => props.onClick()}> {props.value} </button> ); } |
Boardコンポーネント
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
const Board = () => { // 複数の state 変数を使う // https://ja.reactjs.org/docs/hooks-state.html#tip-using-multiple-state-variables const [squares, setSquares] = useState(Array<SquareValue>(9).fill(null)); const [xIsNext, setXIsNext] = useState(true); const handleClick = (i: number): void => { // なぜ.slice()なのかは、下記の[イミュータビリティは何故重要なのか]を参照 // https://ja.reactjs.org/tutorial/tutorial.html#why-immutability-is-important const cp_squares = squares.slice(); cp_squares[i] = (xIsNext) ? 'X' : 'O'; setSquares(cp_squares); setXIsNext(!xIsNext); } const renderSquare = (i: number) => { return ( <Square value={squares[i]} onClick={() => handleClick(i)} /> ); } const calculateWinner = (squares: SquareValue[]): SquareValue => { const lines = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6], ]; for (let i = 0; i < lines.length; i++) { const [a, b, c] = lines[i]; if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { return squares[a]; } } return null; } const displayStatus = (): string => { const winner = calculateWinner(squares); if (winner) { return 'Winner: ' + winner; } else { return 'Next player: ' + ((xIsNext) ? 'X' : 'O'); } } return ( <div> <div className="status">{displayStatus()}</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> ); } |
今回はここまで。次は、タイムトラベル機能の追加を学習しつつ、Typescriptに置き換えていく予定です。