Open10

React + TypeScript学習ログ

ふじしろふじしろ

導入(create-react-app

% npx create-react-app my-app --template typescript
Need to install the following packages:
  create-react-app@5.0.1
Ok to proceed? (y) y
npm WARN deprecated tar@2.2.2: This version of tar is no longer supported, and will not receive security updates. Please upgrade asap.

Creating a new React app in /Users/**/my-app

Installing packages. This might take a couple of minutes.
Installing react, react-dom, and react-scripts with cra-template-typescript...


added 1394 packages in 39s

209 packages are looking for funding
  run `npm fund` for details

Initialized a git repository.

Installing template dependencies using npm...

added 35 packages, and changed 1 package in 2s

209 packages are looking for funding
  run `npm fund` for details

We detected TypeScript in your project (src/App.test.tsx) and created a tsconfig.json file for you.

Your tsconfig.json has been populated with default values.

Removing template package using npm...


removed 1 package, and audited 1429 packages in 1s

209 packages are looking for funding
  run `npm fund` for details

6 high severity vulnerabilities

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.

Created git commit.

Success! Created my-app at /Users/**/my-app
Inside that directory, you can run several commands:

  npm start
    Starts the development server.

  npm run build
    Bundles the app into static files for production.

  npm test
    Starts the test runner.

  npm run eject
    Removes this tool and copies build dependencies, configuration files
    and scripts into the app directory. If you do this, you can’t go back!

We suggest that you begin by typing:

  cd my-app
  npm start

Happy hacking!
ふじしろふじしろ

ベストなディレクトリ構成とかある?->公式としてはない。

考えすぎない
まだプロジェクトを始めたばかりなら、ファイル構成を決めるのに 5 分以上かけないようにしましょう。上述の方法の 1 つを選ぶか、自分自身の方法を考えて、コードを書き始めましょう! おそらく実際のコードをいくらか書けば、なんにせよ考え直したくなる可能性が高いでしょう。

ふじしろふじしろ

POSTリクエストを送りたい(非同期HTTP通信したい)-> useState + Axios

それぞれの担当範囲

  • useState:フォーム入力値の取得
  • Axios:HTTPリクエスト

useState使用法参考

Axios公式

Axios使用法参考

他の候補

ふじしろふじしろ

包括的にエラーハンドリングしたい->react-error-boundaryを導入しよう

前提
React純正のerror-blundary機能ではキャッチできないエラーがある。

error boundary は以下のエラーをキャッチしません:

  • イベントハンドラ(詳細)
  • 非同期コード(例:setTimeout や requestAnimationFrame のコールバック)
  • サーバサイドレンダリング
  • (子コンポーネントではなく)error boundary 自身がスローしたエラー

全部まとめてキャッチしたいなら、react-error-boundary

GitHubページ

使い方参考記事

ふじしろふじしろ

外部リソースのデータを取得して表示したい->useState + useEffect + Axios

それぞれの役割は以下の通り

  • Axios:HTTPリクエスト(GET)によるデータ取得
  • useState:Axiosが取得したデータの保持
  • useEffect:レンダリング後に処理を実行する
ふじしろふじしろ

非同期処理の成功・失敗の確定後にエラーハンドリングしたい -> Suspense機能

やろうとしたこと

  1. useEffect内でリストを取得する非同期処理(GETリクエスト)
  2. 取得したリストから指定の要素を検索(Array.find())
  3. 要素の有無を判定。結果に応じて表示を変える
    • 指定の要素がある -> 通常画面表示
    • 指定の要素がない -> エラーを投げる
      • エラーは前述のreact-error-boundaryにキャッチされ、エラーページが表示される

直面した課題
非同期で指定の要素を取得しようとしているため、3の判定のタイミングでは必ずfalseになり、エラーページへ遷移してしまう

実現したいこと

  • 要素有無の判定処理を非同期処理完了を待ってから実施したい

試したこと

useLayoutEffectフック -> 失敗

useLayoutEffectは処理実行タイミングが、useEffectより早い。

useLayoutEffectで非同期処理を実施し、useEffectで判定を行う

結果:useEffectはuseLayoutEffectの実行完了を待ってくれるわけではないため、非同期処理が長引けばエラーとなる。

useEffect(useLayoutEffect)フックの第二引数を使う -> 失敗

第二引数を指定することで、処理を実行するタイミングを非同期処理完了後にする

結果:レンダリング時の初回実行を避けられず失敗

Suspense機能を使う -> 成功

Suspense機能とは?

これで非同期処理を管理し、完了後に判定処理を実施する形で実装。

結果:参考記事をもとに実装し、どうにか成功。理解は浅いのでもっといい書き方がありそうな気がする。

参考

ふじしろふじしろ

アプリ全体で、最新のステートを共有したい -> useState + proprs + React.FC

  1. 一番の親コンポーネント(Appとか)でuseState宣言
  2. 子コンポーネントにプロパティとして渡す
  3. TypeScriptの場合、ちゃんと型定義していないとここでエラー
  4. 型エラーが発生したらコンポーネントにReact.FC型を宣言する。
  5. functionでコンポーネントを定義していたりするなら、書き換えのためにここでconstによる定義に変更する。

※functionによる定義というのは以下のようなやり方

function App () {
    return <div>...</div>;
}

上記をconstで定義するやり方に直すと以下のような感じになる。

const App = () => {
    return <div>...</div>;
}

propsとしてステートをやりとりするにはさらにReact.FC型をつけて以下のような感じにする
<Child>は子コンポーネントを表す

const App: React.FC<{ props: **propsの型** }> = ( props ) => {
    return <Child props={props} .../>;
}

React.FCについての参考