{"id":21096293,"url":"https://github.com/imamachi-n/react-typescript-sfc","last_synced_at":"2026-04-11T05:31:37.039Z","repository":{"id":68754324,"uuid":"236317379","full_name":"Imamachi-n/react-typescript-sfc","owner":"Imamachi-n","description":"Single File Components for React \u0026 TypeScript","archived":false,"fork":false,"pushed_at":"2020-03-09T08:06:26.000Z","size":16308,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-01-03T14:38:51.060Z","etag":null,"topics":["eslint","material-ui","prettier","react","react-hooks","react-router","redux","styled-components","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Imamachi-n.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-01-26T13:41:04.000Z","updated_at":"2020-03-09T08:06:28.000Z","dependencies_parsed_at":"2023-03-28T20:48:38.448Z","dependency_job_id":null,"html_url":"https://github.com/Imamachi-n/react-typescript-sfc","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Imamachi-n/react-typescript-sfc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Imamachi-n%2Freact-typescript-sfc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Imamachi-n%2Freact-typescript-sfc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Imamachi-n%2Freact-typescript-sfc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Imamachi-n%2Freact-typescript-sfc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Imamachi-n","download_url":"https://codeload.github.com/Imamachi-n/react-typescript-sfc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Imamachi-n%2Freact-typescript-sfc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31669600,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T17:19:37.612Z","status":"online","status_checked_at":"2026-04-11T02:00:05.776Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["eslint","material-ui","prettier","react","react-hooks","react-router","redux","styled-components","typescript"],"created_at":"2024-11-19T22:34:44.262Z","updated_at":"2026-04-11T05:31:37.004Z","avatar_url":"https://github.com/Imamachi-n.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Typescript \u0026 React で Single File Components\n\n経年劣化に耐える React のソフトウェア設計を考えるためのサンプルプロジェクト。  \n学習目的で、実際に React を使ってアプリケーション開発を行う上で必要だと思ったものをまとめてみました。\n\n## 目次\n\n\u003c!-- TOC --\u003e\n\n- [Typescript \u0026 React で Single File Components](#typescript--react-%e3%81%a7-single-file-components)\n  - [目次](#%e7%9b%ae%e6%ac%a1)\n  - [デモ](#%e3%83%87%e3%83%a2)\n    - [URL（デプロイ先）](#url%e3%83%87%e3%83%97%e3%83%ad%e3%82%a4%e5%85%88)\n    - [画面スクリーンショット](#%e7%94%bb%e9%9d%a2%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88)\n      - [トップページ - スクロール](#%e3%83%88%e3%83%83%e3%83%97%e3%83%9a%e3%83%bc%e3%82%b8---%e3%82%b9%e3%82%af%e3%83%ad%e3%83%bc%e3%83%ab)\n      - [レスポンシブ UI（Mobile 用と Desktop 用）](#%e3%83%ac%e3%82%b9%e3%83%9d%e3%83%b3%e3%82%b7%e3%83%96-uimobile-%e7%94%a8%e3%81%a8-desktop-%e7%94%a8)\n  - [設計・アーキテクチャ](#%e8%a8%ad%e8%a8%88%e3%83%bb%e3%82%a2%e3%83%bc%e3%82%ad%e3%83%86%e3%82%af%e3%83%81%e3%83%a3)\n    - [Single File Components for React](#single-file-components-for-react)\n    - [CloudFront/S3 with AWS CDK](#cloudfronts3-with-aws-cdk)\n  - [詳細](#%e8%a9%b3%e7%b4%b0)\n    - [TypeScript \u0026 React のプロジェクトを作成](#typescript--react-%e3%81%ae%e3%83%97%e3%83%ad%e3%82%b8%e3%82%a7%e3%82%af%e3%83%88%e3%82%92%e4%bd%9c%e6%88%90)\n    - [絶対パスで React コンポーネントをインポートできるようにする](#%e7%b5%b6%e5%af%be%e3%83%91%e3%82%b9%e3%81%a7-react-%e3%82%b3%e3%83%b3%e3%83%9d%e3%83%bc%e3%83%8d%e3%83%b3%e3%83%88%e3%82%92%e3%82%a4%e3%83%b3%e3%83%9d%e3%83%bc%e3%83%88%e3%81%a7%e3%81%8d%e3%82%8b%e3%82%88%e3%81%86%e3%81%ab%e3%81%99%e3%82%8b)\n    - [ESLint \u0026 Prettier の導入](#eslint--prettier-%e3%81%ae%e5%b0%8e%e5%85%a5)\n      - [eslint-config-airbnb](#eslint-config-airbnb)\n      - [eslint-plugin-react](#eslint-plugin-react)\n      - [eslint-plugin-react-hooks](#eslint-plugin-react-hooks)\n      - [eslint-plugin-import](#eslint-plugin-import)\n      - [eslint-plugin-jsx-a11y](#eslint-plugin-jsx-a11y)\n      - [eslint-plugin-jest](#eslint-plugin-jest)\n      - [eslint-plugin-prefer-arrow](#eslint-plugin-prefer-arrow)\n      - [eslint-plugin-mdx](#eslint-plugin-mdx)\n      - [@typescript-eslint](#typescript-eslint)\n      - [@typescript-eslint/parser](#typescript-eslintparser)\n      - [@typescript-eslint/eslint-plugin](#typescript-eslinteslint-plugin)\n      - [eslint-plugin-prettier](#eslint-plugin-prettier)\n    - [Stylelint の導入（オプション）](#stylelint-%e3%81%ae%e5%b0%8e%e5%85%a5%e3%82%aa%e3%83%97%e3%82%b7%e3%83%a7%e3%83%b3)\n      - [Styled-components](#styled-components)\n      - [stylelint-config-prettier](#stylelint-config-prettier)\n    - [husky \u0026 lint-staged の導入](#husky--lint-staged-%e3%81%ae%e5%b0%8e%e5%85%a5)\n      - [lint-staged](#lint-staged)\n      - [hasky](#hasky)\n    - [Redux の導入](#redux-%e3%81%ae%e5%b0%8e%e5%85%a5)\n      - [複数の reducer を結合する](#%e8%a4%87%e6%95%b0%e3%81%ae-reducer-%e3%82%92%e7%b5%90%e5%90%88%e3%81%99%e3%82%8b)\n    - [React Router の導入](#react-router-%e3%81%ae%e5%b0%8e%e5%85%a5)\n      - [画面遷移時のスクロール位置の初期化](#%e7%94%bb%e9%9d%a2%e9%81%b7%e7%a7%bb%e6%99%82%e3%81%ae%e3%82%b9%e3%82%af%e3%83%ad%e3%83%bc%e3%83%ab%e4%bd%8d%e7%bd%ae%e3%81%ae%e5%88%9d%e6%9c%9f%e5%8c%96)\n      - [React Router と Redux の統合](#react-router-%e3%81%a8-redux-%e3%81%ae%e7%b5%b1%e5%90%88)\n    - [Styled-components の導入](#styled-components-%e3%81%ae%e5%b0%8e%e5%85%a5)\n      - [Global CSS を指定する方法](#global-css-%e3%82%92%e6%8c%87%e5%ae%9a%e3%81%99%e3%82%8b%e6%96%b9%e6%b3%95)\n    - [Material-UI の導入](#material-ui-%e3%81%ae%e5%b0%8e%e5%85%a5)\n      - [Styled-components で定義したスタイルを優先する](#styled-components-%e3%81%a7%e5%ae%9a%e7%be%a9%e3%81%97%e3%81%9f%e3%82%b9%e3%82%bf%e3%82%a4%e3%83%ab%e3%82%92%e5%84%aa%e5%85%88%e3%81%99%e3%82%8b)\n      - [テーマカラーを設定する](#%e3%83%86%e3%83%bc%e3%83%9e%e3%82%ab%e3%83%a9%e3%83%bc%e3%82%92%e8%a8%ad%e5%ae%9a%e3%81%99%e3%82%8b)\n      - [上部に固定されたヘッダーを作成](#%e4%b8%8a%e9%83%a8%e3%81%ab%e5%9b%ba%e5%ae%9a%e3%81%95%e3%82%8c%e3%81%9f%e3%83%98%e3%83%83%e3%83%80%e3%83%bc%e3%82%92%e4%bd%9c%e6%88%90)\n      - [Grid React component のスクリーンサイズに応じた調節](#grid-react-component-%e3%81%ae%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b5%e3%82%a4%e3%82%ba%e3%81%ab%e5%bf%9c%e3%81%98%e3%81%9f%e8%aa%bf%e7%af%80)\n      - [画面サイズに合わせて、React コンポーネントを表示・非表示をコントロール](#%e7%94%bb%e9%9d%a2%e3%82%b5%e3%82%a4%e3%82%ba%e3%81%ab%e5%90%88%e3%82%8f%e3%81%9b%e3%81%a6react-%e3%82%b3%e3%83%b3%e3%83%9d%e3%83%bc%e3%83%8d%e3%83%b3%e3%83%88%e3%82%92%e8%a1%a8%e7%a4%ba%e3%83%bb%e9%9d%9e%e8%a1%a8%e7%a4%ba%e3%82%92%e3%82%b3%e3%83%b3%e3%83%88%e3%83%ad%e3%83%bc%e3%83%ab)\n      - [画面トップへスクロールして戻るボタン](#%e7%94%bb%e9%9d%a2%e3%83%88%e3%83%83%e3%83%97%e3%81%b8%e3%82%b9%e3%82%af%e3%83%ad%e3%83%bc%e3%83%ab%e3%81%97%e3%81%a6%e6%88%bb%e3%82%8b%e3%83%9c%e3%82%bf%e3%83%b3)\n    - [React Helmet の導入](#react-helmet-%e3%81%ae%e5%b0%8e%e5%85%a5)\n      - [ヘッダー情報を追加する](#%e3%83%98%e3%83%83%e3%83%80%e3%83%bc%e6%83%85%e5%a0%b1%e3%82%92%e8%bf%bd%e5%8a%a0%e3%81%99%e3%82%8b)\n    - [Storybook の導入（Create React App 用）](#storybook-%e3%81%ae%e5%b0%8e%e5%85%a5create-react-app-%e7%94%a8)\n      - [Storybook の作成](#storybook-%e3%81%ae%e4%bd%9c%e6%88%90)\n      - [MDX で Storybook ドキュメントを作成する](#mdx-%e3%81%a7-storybook-%e3%83%89%e3%82%ad%e3%83%a5%e3%83%a1%e3%83%b3%e3%83%88%e3%82%92%e4%bd%9c%e6%88%90%e3%81%99%e3%82%8b)\n      - [Storybook Deployer を使って GitHub Pages へ Storybook をデプロイする](#storybook-deployer-%e3%82%92%e4%bd%bf%e3%81%a3%e3%81%a6-github-pages-%e3%81%b8-storybook-%e3%82%92%e3%83%87%e3%83%97%e3%83%ad%e3%82%a4%e3%81%99%e3%82%8b)\n    - [Docker 上で開発環境をセットアップする](#docker-%e4%b8%8a%e3%81%a7%e9%96%8b%e7%99%ba%e7%92%b0%e5%a2%83%e3%82%92%e3%82%bb%e3%83%83%e3%83%88%e3%82%a2%e3%83%83%e3%83%97%e3%81%99%e3%82%8b)\n  - [VSCode の設定について](#vscode-%e3%81%ae%e8%a8%ad%e5%ae%9a%e3%81%ab%e3%81%a4%e3%81%84%e3%81%a6)\n    - [拡張機能の管理](#%e6%8b%a1%e5%bc%b5%e6%a9%9f%e8%83%bd%e3%81%ae%e7%ae%a1%e7%90%86)\n    - [VSCode の設定の管理](#vscode-%e3%81%ae%e8%a8%ad%e5%ae%9a%e3%81%ae%e7%ae%a1%e7%90%86)\n  - [既存の React プロジェクトのアップデート](#%e6%97%a2%e5%ad%98%e3%81%ae-react-%e3%83%97%e3%83%ad%e3%82%b8%e3%82%a7%e3%82%af%e3%83%88%e3%81%ae%e3%82%a2%e3%83%83%e3%83%97%e3%83%87%e3%83%bc%e3%83%88)\n    - [Create React App](#create-react-app)\n    - [Storybook](#storybook)\n    - [React などの他のパッケージのアップグレード](#react-%e3%81%aa%e3%81%a9%e3%81%ae%e4%bb%96%e3%81%ae%e3%83%91%e3%83%83%e3%82%b1%e3%83%bc%e3%82%b8%e3%81%ae%e3%82%a2%e3%83%83%e3%83%97%e3%82%b0%e3%83%ac%e3%83%bc%e3%83%89)\n  - [参考資料](#%e5%8f%82%e8%80%83%e8%b3%87%e6%96%99)\n  - [公式ドキュメント](#%e5%85%ac%e5%bc%8f%e3%83%89%e3%82%ad%e3%83%a5%e3%83%a1%e3%83%b3%e3%83%88)\n\n\u003c!-- /TOC --\u003e\n\n## デモ\n\n### URL（デプロイ先）\n\n**Storybook - スタイルガイド（GitHub Pages）**  \n\u003chttps://imamachi-n.github.io/react-typescript-sfc/\u003e\n\n**React アプリケーション（AWS: CloudFront/S3）**  \n準備中。。。\n\n### 画面スクリーンショット\n\n#### トップページ - スクロール\n\n- ランディングページによくある、リンクをクリックすると自動スクロールされる仕組み。\n- トップページの先頭に戻るボタンを表示（スクロールをトリガーにする）。\n\n![React_SFC_1](./img/React_SFC_1.gif)\n\n#### レスポンシブ UI（Mobile 用と Desktop 用）\n\n- Desktop 用の画面では、ナビゲーションをページ上部に表示させる。\n- Mobile 用の画面では、ナビゲーションをページ下部に表示させる（指で押しやすいため）。\n\n![React_SFC_2](./img/React_SFC_2.gif)\n\n## 設計・アーキテクチャ\n\n### Single File Components for React\n\n準備中。\n\n**参考資料**  \n[経年劣化に耐える ReactComponent の書き方](https://qiita.com/Takepepe/items/41e3e7a2f612d7eb094a)\n\n### CloudFront/S3 with AWS CDK\n\n準備中。\n\n## 詳細\n\n### TypeScript \u0026 React のプロジェクトを作成\n\n```bash\nnpx create-react-app react-typescript-sfc --template typescript\n```\n\nAdding TypeScript  \n\u003chttps://create-react-app.dev/docs/adding-typescript/\u003e\n\n### 絶対パスで React コンポーネントをインポートできるようにする\n\n相対パスだと、リファクタリングによってコンポーネントの配置を変更した場合に、インポート先もすべて変更する必要が出てくる。絶対パスを指定することにより、上記の問題を回避する。\n\n設定方法としては、`tsconfig.json` に以下の設定を追加するだけ。\n\n```json\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \"src\"\n  },\n  \"include\": [\"src\"]\n}\n```\n\n例えば、`components/Button` を以下のように絶対パスを使ってインポートできるようになる。\n\n```tsx\nimport Button from 'components/Button';\n```\n\n\u003c!-- VSCode を使っている場合、絶対パスを使用すると `Cannot find module` と怒られるはずなので、VSCode の `settings.json` に以下の設定を追加する。\n\n```json\n{\n  \"typescript.preferences.importModuleSpecifier\": \"non-relative\"\n}\n``` --\u003e\n\nおそらく、絶対パスにすると補完が効かなくなるので、さらに、`path-intellisense` を拡張機能として追加する。\n\n**参考資料**  \n[Create React App - Absolute Imports](https://create-react-app.dev/docs/importing-a-component/#absolute-imports)  \n[VS Code: “Cannot find module” from root path](https://stackoverflow.com/questions/55063550/vs-code-cannot-find-module-from-root-path)\n\n### ESLint \u0026 Prettier の導入\n\nまず、コーディングスタイルを統一するために、ESLint と Prettier の導入を行う。\n\n```bash\nyarn add -D \\\neslint @types/eslint \\\nprettier @types/prettier \\\n@typescript-eslint/eslint-plugin \\\n@typescript-eslint/parser \\\neslint-config-airbnb \\\neslint-config-prettier \\\neslint-plugin-import \\\neslint-plugin-react \\\neslint-plugin-react-hooks\neslint-plugin-jsx-a11y \\\neslint-plugin-jest \\\neslint-plugin-prefer-arrow \\\neslint-plugin-mdx \\\neslint-plugin-prettier \\\n@types/eslint-plugin-prettier\n```\n\n以下の各種設定を 設定ファイル `.eslitrc.js` に記述する。デフォルトの `.eslitrc` の JSON ファイルの場合、キーにいちいちダブルクオーテーションをつけないといけないので、`JSファイル` にしたほうが書きやすいと思う。\n\n#### eslint-config-airbnb\n\nAirBnb が提供する ESLint の有名な共通設定を導入する。\n`eslint-config-airbnb` を導入する際、以下のパッケージが必要になる。\n\n- eslint\n- eslint-plugin-import\n- eslint-plugin-react\n- eslint-plugin-react-hooks\n- eslint-plugin-jsx-a11y\n- @typescript-eslint/parser\n\neslint-config-airbnb の導入  \n\u003chttps://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb#eslint-config-airbnb-1\u003e\n\n#### eslint-plugin-react\n\n`eslint-plugin-react` は React 固有の lint の設定を追加するためのプラグイン。使用するために、`extends` と `plugins` に設定を追加する。\n\n```js\nextends: [\n  'eslint:recommended',\n  'plugin:react/recommended',\n],\n\nplugins: [\n  'react'\n],\n```\n\nまた、React のバージョンを自動的に特定するために、`detect` の設定を行う（将来的に、`detect` がデフォルトになる予定なので、いずれ設定する必要がなくなる）。\n\n```js\nsettings: {\n  react: {\n    version: 'detect',\n  },\n}\n```\n\nさらに、JSX のサポート（ESLint 2+）を追加するために、\n\n```js\nparserOptions: {\n  ecmaFeatures: {\n    jsx: true,\n  },\n},\n```\n\neslint-plugin-react の設定  \n\u003chttps://github.com/yannickcr/eslint-plugin-react#configuration\u003e\n\n#### eslint-plugin-react-hooks\n\n`eslint-plugin-react-hooks`は、React Hook に対する lint を設定するためのプラグイン。マニュアル設定を適応する場合、以下のように設定する。\n\n```js\nplugins: [\n  \"react-hooks\"\n],\n\nrules: {\n  'react-hooks/rules-of-hooks': 'error',\n  'react-hooks/exhaustive-deps': 'error',\n},\n```\n\n#### eslint-plugin-import\n\n`eslint-plugin-import` は ES2015+ (ES6+) import/export syntax の lint に使われる。\nデフォルトではすべてのルールが無効化されているので、`extends` 内でプラグインの設定を行うか、\n\n```js\nextends: [\n  'eslint:recommended',\n  'plugin:import/errors',\n  'plugin:import/warnings',\n],\n```\n\n個別にルールを `rules` 内に書き込む必要がある（両方、設定することも可能）。\n\n```js\nplugins: [\n    'import',\n],\n\nrules: {\n    'import/extensions': [\n      'error',\n      'always',\n      {\n        js: 'never',\n        jsx: 'never',\n        ts: 'never',\n        tsx: 'never',\n      },\n    ],\n    'import/prefer-default-export': 'off',\n}\n```\n\nまた、TypeScript を使っている場合は、次の設定を追加する必要がある。このとき、`@typescript-eslint/parser` パッケージが依存パッケージに含める必要がある。\n\n```js\nextends: [\n  'eslint:recommended',\n  'plugin:import/errors',\n  'plugin:import/warnings',\n  'plugin:import/typescript', // 追加\n],\n```\n\neslint-plugin-import のインストール方法  \n\u003chttps://github.com/benmosher/eslint-plugin-import#installation\u003e\n\nルールを適応するファイルを以下のように指定する。`import/resolver` では、`src` ディレクトリ以下の `ts` や `tsx` などの拡張子を持つファイルのみを対象とする。\n\n```js\nsettings: {\n  'import/resolver': {\n    node: {\n      extensions: ['.js', 'jsx', '.ts', '.tsx'],\n      paths: ['src'],\n    },\n  },\n}\n```\n\nまた、`import/parsers` を使うことで、対象のファイルに対して、指定した parser を使用することができる。以下では、`ts` や `tsx` の拡張子を持つファイルに対して、TypeScript 用の parser を使うように設定している。\n\n```js\nsettings: {\n  'import/parsers': {\n    '@typescript-eslint/parser': ['.ts', '.tsx'],\n  },\n}\n```\n\neslint-plugin-import の設定  \n\u003chttps://github.com/benmosher/eslint-plugin-import#settings\u003e\n\n#### eslint-plugin-jsx-a11y\n\n`eslint-plugin-jsx-a11y` は Web アクセシビリティに関する lint を行うためのプラグイン。`plugins` で以下のように設定する。\n\n```js\n\"plugins\": [\n  \"jsx-a11y\",\n]\n```\n\n推奨設定を適応する場合、以下のように設定する。\n\n```js\nextends: [\n  'plugin:jsx-a11y/recommended',\n]\n```\n\neslint-plugin-jsx-a11y の使い方  \n\u003chttps://github.com/evcohen/eslint-plugin-jsx-a11y#usage\u003e\n\n#### eslint-plugin-jest\n\n`eslint-plugin-jest` は Jest に対する lint を行うためのプラグイン。以下では、推奨設定とスタイルを強制する設定を示した。\n\n```js\nextends: [\n  'plugin:jest/recommended',\n  'plugin:jest/style',\n],\n\nplugins: [\n  'jest',\n],\n```\n\nまた、Jest が提供するグローバル変数をホワイトリストに追加するために、以下のように設定を行う。\n\n```js\nenv: {\n  'jest/globals': true,\n},\n```\n\neslint-plugin-jest の使い方  \n\u003chttps://github.com/jest-community/eslint-plugin-jest#usage\u003e\n\n#### eslint-plugin-prefer-arrow\n\n`eslint-plugin-prefer-arrow` はアロー関数に関する lint を行うためのプラグイン。以下のように設定を行う。\n\n```js\nplugins: [\n  'prefer-arrow',\n],\n\nrules: {\n  'prefer-arrow/prefer-arrow-functions': [\n    'error',\n    {\n      disallowPrototype: true,\n      singleReturnOnly: true,\n      classPropertiesAllowed: false,\n    },\n  ],\n}\n```\n\neslint-plugin-prefer-arrow の使い方  \n\u003chttps://github.com/TristonJ/eslint-plugin-prefer-arrow#installations\u003e\n\n#### eslint-plugin-mdx\n\n`eslint-plugin-mdx` は MDX ファイル（JSX/TSX 内に markdown ファイルがかけるようにした拡張構文）を lint するためのプラグイン。以下のように設定を行う。\n\n```js\n{\n  extends: [\"plugin:mdx/recommended\"]\n}\n```\n\neslint-plugin-mdx の使い方  \n\u003chttps://github.com/mdx-js/eslint-mdx#install\u003e\n\n#### @typescript-eslint\n\n#### @typescript-eslint/parser\n\nTypeScript で型の情報を必要とする場合は、必須の設定。\n\n```js\nparserOptions: {\n  project: './tsconfig.json',\n}\n```\n\n@typescript-eslint/parser の使い方  \n\u003chttps://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser#parseroptionsproject\u003e\n\n#### @typescript-eslint/eslint-plugin\n\n`@typescript-eslint/eslint-plugin` は TypeScript の lint を行うためのプラグイン。`@typescript-eslint/parser` がインストールされていることが前提。推奨設定は以下のように設定を行う。\n\n```js\nextends: [\n  'plugin:import/typescript',\n  'plugin:@typescript-eslint/eslint-recommended',\n  'plugin:@typescript-eslint/recommended',\n],\n\nparser: '@typescript-eslint/parser',\nplugins: [\n  '@typescript-eslint',\n],\nrules: {\n  '@typescript-eslint/explicit-function-return-type': 'off',\n  '@typescript-eslint/explicit-member-accessibility': 'off',\n  indent: 'off',\n  '@typescript-eslint/indent': 'off',\n  '@typescript-eslint/no-unnecessary-type-assertion': 'error',\n}\n```\n\n@typescript-eslint/eslint-plugin の使い方  \n\u003chttps://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#usage\u003e\n\n#### eslint-plugin-prettier\n\n`eslint-plugin-prettier` は Prettier と ESLint を連携させるためのプラグイン。推奨設定は以下のように設定を行う。また、他のプラグインと連携を行うことできる。\n\n```js\nextends: [\n  'plugin:prettier/recommended',\n  'prettier/react',\n  'prettier/standard',\n],\n```\n\nマニュアルで設定を変更する場合は、以下のように設定を行う。\n\n```js\nextends: [\n  'prettier',\n],\n\nplugins: [\n  'prettier',\n],\n\nrules: {\n  'prettier/prettier': 'error',\n}\n```\n\neslint-plugin-prettier の使い方  \n\u003chttps://github.com/prettier/eslint-plugin-prettier#recommended-configuration\u003e  \n連携できる ESLint プラグインの一覧  \n\u003chttps://github.com/prettier/eslint-config-prettier/blob/master/README.md#installation\u003e\n\n### Stylelint の導入（オプション）\n\nStyled-components に Stylelint と Prettier を導入する。ただし、Styled-components の場合、`--fix` オプションを使うことができないため、自動で修正することは不可能（問題箇所の検知のみ可能）。\n\n```bash\nyarn add -D \\\nstylelint \\\n@types/stylelint \\\nstylelint-processor-styled-components \\\nstylelint-config-styled-components \\\nstylelint-config-recommended \\\nstylelint-config-prettier\n```\n\n#### Styled-components\n\n`.stylelintrc` ファイルを作成して、以下の Styled-components の設定を追加する。\n\n```json\n{\n  \"processors\": [\"stylelint-processor-styled-components\"],\n  \"extends\": [\n    \"stylelint-config-recommended\",\n    \"stylelint-config-styled-components\"\n  ]\n}\n```\n\nStyled-components tooling  \n\u003chttps://styled-components.com/docs/tooling#stylelint\u003e\n\n#### stylelint-config-prettier\n\nPrettier と競合するルールを排除する。\n\n```json\n{\n  \"extends\": [\"stylelint-config-prettier\"]\n}\n```\n\nstylelint-config-prettier の使い方  \n\u003chttps://github.com/prettier/stylelint-config-prettier#installation\u003e\n\n### husky \u0026 lint-staged の導入\n\n```bash\nyarn add husky lint-staged\n```\n\n#### lint-staged\n\n`lint-staged` を使うことで、staged git ファイルのみに対して lint をコマンドで実行することができる。\n\n```json\n{\n  \"lint-staged\": {\n    \"src/**/*.{js,jsx,ts,tsx}\": [\"eslint --fix\", \"git add\"]\n  }\n}\n```\n\nlint-staged の使い方  \n\u003chttps://github.com/okonet/lint-staged#configuration\u003e\n\n#### hasky\n\n`husky` は git での commit・push の前に実行するコマンドを設定できる。ここでは、`lint-staged` と合わせて使用し、コミット時に lint が実行されるように設定する。`package.json` を以下のように設定する。\n\n```json\n// package.json\n{\n  \"husky\": {\n    \"hooks\": {\n      \"pre-commit\": \"lint-staged\"\n    }\n  }\n}\n```\n\nHusky の使い方  \n\u003chttps://github.com/typicode/husky#install\u003e\n\n### Redux の導入\n\n```bash\nyarn add redux react-redux @types/redux @types/react-redux\n```\n\nReact Redux - Quick Start  \n\u003chttps://react-redux.js.org/introduction/quick-start\u003e\n\nRedux - Configuring Your Store  \n\u003chttps://redux-docs.netlify.com/recipes/configuring-your-store/\u003e\n\n#### 複数の reducer を結合する\n\nUsing `combineReducers`  \n\u003chttps://redux-docs.netlify.com/recipes/structuring-reducers/using-combinereducers\u003e\n\n### React Router の導入\n\n```bash\nyarn add react-router-dom @types/react-router-dom\n```\n\nReact Router - Quick Start  \n\u003chttps://reacttraining.com/react-router/web/guides/quick-start\u003e\n\n#### 画面遷移時のスクロール位置の初期化\n\nデフォルトの設定では、画面遷移時に前のページのスクロール位置が残ってしまい、ページの最上部から表示されない問題が発生する。\n\n以下の設定を追加し、問題を解消する必要がある。\n\n```tsx\nimport { useEffect } from 'react';\nimport { useLocation } from 'react-router-dom';\n\nexport default function ScrollRestoration() {\n  const { pathname } = useLocation();\n\n  useEffect(() =\u003e {\n    window.scrollTo(0, 0);\n  }, [pathname]);\n\n  return null;\n}\n```\n\n```tsx\nimport React from 'react';\nimport { BrowserRouter as Router } from 'react-router-dom';\nimport ScrollRestoration from 'components/Common/ScrollRestoration';\n\nfunction App() {\n  return (\n    \u003cRouter\u003e\n      \u003cScrollToTop /\u003e\n      \u003cApp /\u003e\n    \u003c/Router\u003e\n  );\n}\n```\n\nReact Router - Scroll Restoration  \n\u003chttps://reacttraining.com/react-router/web/guides/scroll-restoration\u003e\n\n#### React Router と Redux の統合\n\nReact Router - Redux Integration  \n\u003chttps://reacttraining.com/react-router/web/guides/redux-integration\u003e\n\n### Styled-components の導入\n\n#### Global CSS を指定する方法\n\ncreateGlobalStyle  \n\u003chttps://styled-components.com/docs/api#createglobalstyle\u003e\n\n### Material-UI の導入\n\n```bash\nyarn add @material-ui/core @material-ui/icons\n```\n\nMaterial-UI のインストール  \n\u003chttps://material-ui.com/getting-started/installation/\u003e\n\n#### Styled-components で定義したスタイルを優先する\n\nCSS インジェクションの順番を、Styled-components が最も優先されるように指定する。\n\nルートコンポーネントをラップする形で、`StylesProvider` コンポーネントを使用し、プロパティに `injectFirst` を指定することで、Styled-components を最も優先するように設定できる。\n\n```tsx\nimport { StylesProvider } from '@material-ui/core/styles';\n\nReactDOM.render(\n  \u003cStylesProvider injectFirst\u003e\n    \u003cApp /\u003e\n  \u003c/StylesProvider\u003e,\n  document.getElementById('root'),\n);\n```\n\nControlling priority  \n\u003chttps://material-ui.com/guides/interoperability/#controlling-priority-%EF%B8%8F-3\u003e\n\ninjectFirst  \n\u003chttps://material-ui.com/styles/advanced/#injectfirst\u003e\n\n#### テーマカラーを設定する\n\nMaterial-UI の `ThemeProvider` を用いて、カスタムテーマを対象のコンポーネントに適応する。このとき、Styled-components でも、Material-UI のカスタムテーマを使うために、`ThemeProvider` を併用する。\n\nモジュール名が同じため、以下のように、Material-UI の `ThemeProvider` を `MaterialThemeProvider`、Styled-components の `ThemeProvider` を `StyledThemeProvider` と定義する。\n\n```tsx\nimport { ThemeProvider as MaterialThemeProvider } from '@material-ui/styles';\nimport { ThemeProvider as StyledThemeProvider } from 'styled-components';\n\nReactDOM.render(\n  \u003cMaterialThemeProvider theme={theme}\u003e\n    \u003cStyledThemeProvider theme={theme}\u003e\n      \u003cApp /\u003e\n    \u003c/StyledThemeProvider\u003e\n  \u003c/MaterialThemeProvider\u003e,\n  document.getElementById('root'),\n);\n```\n\nカスタムテーマを使用する場合は、以下のように `props` からアクセスできる。ただし、上記の設定のみだと、TypeScript の場合、theme の型が `any` になってしまう。\n\n```tsx\nimport { AppBar } from '@material-ui/core';\nimport styled from 'styled-components';\n\nconst StyledAppBar = styled(AppBar)`\n  background-color: ${props =\u003e props.theme.palette.primary.main};\n`;\n```\n\nそこで、Styled-components の TypeScript の型を拡張する。具体的には、Material-UI の Theme を継承した、`DefaultTheme` を新たに定義する。ファイル名は、`styled.d.ts` とする。\n\n`DefaultTheme` は `props.theme` のインターフェースとして使用される。デフォルトでは、`DefaultTheme` は未定義なので、Material-UI の Theme を継承して、カスタムテーマの型を定義している。\n\n```tsx\n// import original module declarations\nimport 'styled-components';\nimport { Theme } from '@material-ui/core';\n\n// and extend them!\ndeclare module 'styled-components' {\n  export interface DefaultTheme extends Theme {} // eslint-disable-line\n}\n```\n\nESLint のせいで、interface の中身が空の場合、エラーとなるため、`// eslint-disable-line` を指定して、ESLint を無視する（あくまで例外的な処置）。\nこれにより、VSCode 上で補完が効くようになる。\n\n**参考資料**  \n[Material-UI のテーマのカスタマイズ](https://material-ui.com/customization/palette/#customization)  \n[Material-UI のカスタムテーマをコンポーネントに適応する方法](https://material-ui.com/customization/theming/#theme-provider)  \n[How to use Material-UI theme with styled-components?](https://github.com/mui-org/material-ui/issues/10098)  \n[Styled-components で TypeScript の型定義ファイルを設定する](https://styled-components.com/docs/api#create-a-declarations-file)  \n[Material-UI と styled components のテーマの共通化](https://qiita.com/Ouvill/items/c6761c32d31ffb11e114#material-ui-%E3%81%A8-styled-components-%E3%81%AE%E3%83%86%E3%83%BC%E3%83%9E%E3%81%AE%E5%85%B1%E9%80%9A%E5%8C%96)\n\n#### 上部に固定されたヘッダーを作成\n\n`React.cloneElement` を使って、子コンポーネントに `elevation` を `props` として渡す。\n\nカスタム Hook である `useScrollTrigger` を使うことで、スクロールをトリガーとして、対象のコンポーネント（ヘッダーなど）を上部に配置する（デフォルトで elevation の値が `4` であり、スクロール時にこれを `0` にすることで、対象のコンポーネントが上部に固定される）。\n\n```tsx\nimport React from 'react';\nimport { useScrollTrigger } from '@material-ui/core';\n\ninterface ScrollProps {\n  children: React.ReactElement;\n}\n\nexport default function ElevationScroll(props: ScrollProps) {\n  const { children } = props;\n\n  const trigger = useScrollTrigger({\n    disableHysteresis: true,\n    threshold: 0,\n  });\n\n  return React.cloneElement(children, {\n    elevation: trigger ? 4 : 0,\n  });\n}\n```\n\n**参考資料**  \n[Material-UI - Elevate App Bar ](https://material-ui.com/components/app-bar/#elevate-app-bar)  \n[React - cloneElement()](https://reactjs.org/docs/react-api.html#cloneelement)\n\n#### Grid React component のスクリーンサイズに応じた調節\n\n```\ninnerWidth  |xs      sm       md       lg       xl\n            |--------|--------|--------|--------|--------\u003e\nwidth       |   xs   |   sm   |   md   |   lg   |   xl\n\nsmUp        |   show | hide\nmdDown      |                     hide | show\n```\n\n**参考資料**  \n[Grid - How it works](https://material-ui.com/components/grid/#how-it-works)  \n[Grid API](https://material-ui.com/api/grid/)\n\n#### 画面サイズに合わせて、React コンポーネントを表示・非表示をコントロール\n\nMobile 用と Desktop 用で画面の表示を切り替えるのに有用。\n\n```tsx\n// 1. Import Layer\nimport React from 'react';\nimport styled from 'styled-components';\nimport { Hidden } from '@material-ui/core';\nimport { ContaineredTitle, Title } from './Title';\nimport { ContaineredScrollButton } from './ScrollButton';\nimport { ContaineredToDoButton } from './TodoButton';\nimport { ContaineredApiButton } from './ApiButton';\n\n// 2. Types Layer\ntype Props = {\n  className?: string;\n};\n\n// 3. DOM Layer\nconst LeftSide: React.FC\u003cProps\u003e = props =\u003e {\n  const { className } = props;\n\n  return (\n    \u003cdiv className={className}\u003e\n      {/* For mobile */}\n      \u003cHidden mdUp\u003e\n        \u003cTitle /\u003e\n      \u003c/Hidden\u003e\n\n      {/* For Desktop */}\n      \u003cHidden smDown\u003e\n        \u003cContaineredTitle /\u003e\n        \u003cContaineredScrollButton /\u003e\n        \u003cContaineredToDoButton /\u003e\n        \u003cContaineredApiButton /\u003e\n      \u003c/Hidden\u003e\n    \u003c/div\u003e\n  );\n};\n\n// 4. Style Layer\nexport const StyledLeftSide = styled(LeftSide)`\n  display: flex;\n`;\n\nexport default StyledLeftSide;\n```\n\nMaterial-UI - Hidden  \n\u003chttps://material-ui.com/components/hidden/#breakpoint-up\u003e\n\n#### 画面トップへスクロールして戻るボタン\n\n**ScrollTop コンポーネント**\n\n```tsx\n// 1. Import Layer\nimport React from 'react';\nimport styled from 'styled-components';\nimport { useScrollTrigger, Zoom } from '@material-ui/core';\n\ntype ContainerProps = {\n  children: React.ReactElement;\n};\n\ntype Props = {\n  className?: string;\n  trigger: boolean;\n  handleClick: (event: React.MouseEvent\u003cHTMLDivElement\u003e) =\u003e void;\n} \u0026 ContainerProps;\n\n// 3. DOM Layer\nconst ScrollTop: React.FC\u003cProps\u003e = props =\u003e {\n  const { className, children, trigger, handleClick } = props;\n\n  return (\n    \u003c\u003e\n      \u003cZoom in={trigger}\u003e\n        \u003cdiv className={className} onClick={handleClick} role=\"presentation\"\u003e\n          {children}\n        \u003c/div\u003e\n      \u003c/Zoom\u003e\n    \u003c/\u003e\n  );\n};\n\n// 4. Style Layer\nexport const StyledScrollTop = styled(ScrollTop)`\n  position: fixed;\n  bottom: ${props =\u003e props.theme.spacing(2)}px;\n  right: ${props =\u003e props.theme.spacing(2)}px;\n`;\n\n// 5. Container Layer\nexport const ContaineredScrollTop: React.FC\u003cContainerProps\u003e = props =\u003e {\n  const trigger = useScrollTrigger({\n    disableHysteresis: true,\n    threshold: 100,\n  });\n\n  const handleClick = (event: React.MouseEvent\u003cHTMLDivElement\u003e) =\u003e {\n    // TODO: アンカーに`id=\"#back-to-top-anchor\"`を設定する必要あり。\n    const anchor = (\n      (event.target as HTMLDivElement).ownerDocument || document\n    ).querySelector('#back-to-top-anchor');\n\n    if (anchor) {\n      anchor.scrollIntoView({ behavior: 'smooth', block: 'center' });\n    }\n  };\n\n  return (\n    \u003cStyledScrollTop {...props} trigger={trigger} handleClick={handleClick} /\u003e\n  );\n};\n\nexport default ContaineredScrollTop;\n```\n\n**ScrollTopButton コンポーネント**\n\n```tsx\n// 1. Import Layer\nimport React from 'react';\nimport styled from 'styled-components';\nimport { ContaineredScrollTop } from 'components/Common/ScrollTop';\nimport { Fab } from '@material-ui/core';\nimport KeyboardArrowUpIcon from '@material-ui/icons/KeyboardArrowUp';\n\n// 2. Types Layer\ntype Props = {\n  className?: string;\n};\n\n// 3. DOM Layer\nconst ScrollTopButton: React.FC\u003cProps\u003e = props =\u003e {\n  const { className } = props;\n\n  return (\n    \u003cdiv className={className}\u003e\n      \u003cContaineredScrollTop {...props}\u003e\n        \u003cFab color=\"primary\" size=\"small\" aria-label=\"scroll back to top\"\u003e\n          \u003cKeyboardArrowUpIcon /\u003e\n        \u003c/Fab\u003e\n      \u003c/ContaineredScrollTop\u003e\n    \u003c/div\u003e\n  );\n};\n\n// 4. Style Layer\nexport const StyledScrollTopButton = styled(ScrollTopButton)``;\n\nexport default StyledScrollTopButton;\n```\n\n**使用例**\n\n```tsx\n// 1. Import Layer\nimport React from 'react';\nimport styled from 'styled-components';\nimport { StyledScrollTopButton } from 'components/Common/ScrollTop/ScrollTopButton';\nimport { Menu } from './components/Menu';\nimport { Contents } from './components/Contents';\n\n// 2. Types Layer\ntype Props = {\n  className?: string;\n};\n\n// 3. DOM Layer\nconst App: React.FC\u003cProps\u003e = props =\u003e {\n  const { className } = props;\n\n  return (\n    \u003cRouter\u003e\n      \u003cdiv className={className}\u003e\n        \u003cMenu /\u003e\n\n        {/* Anchor for ScrollToTop */}\n        \u003cdiv id=\"back-to-top-anchor\" /\u003e\n\n        \u003cContents /\u003e\n\n        {/* ScrollToTop Button */}\n        \u003cStyledScrollTopButton /\u003e\n      \u003c/div\u003e\n    \u003c/Router\u003e\n  );\n};\n\n// 4. Style Layer\nconst StyledApp = styled(App)`\n  background-color: #282c34;\n  font-size: calc(10px + 2vmin);\n  color: white;\n`;\n\nexport default StyledApp;\n```\n\n[Material-UI - Back to top](https://material-ui.com/components/app-bar/#back-to-top)  \n[MDN - Element.scrollIntoView()](https://developer.mozilla.org/ja/docs/Web/API/Element/scrollIntoView)\n\n### React Helmet の導入\n\n```bash\nyarn add react-helmet @types/react-helmet\n```\n\n#### ヘッダー情報を追加する\n\nメタ情報やタイトルなどをヘッダー情報として追加することができる。\n\n```tsx\n// 1. Import Layer\nimport React from 'react';\nimport { Helmet } from 'react-helmet';\n\n// 2. Types Layer\ntype Props = {};\n\n// 3. DOM Layer\nexport const Header: React.FC\u003cProps\u003e = () =\u003e {\n  return (\n    \u003c\u003e\n      \u003cHelmet\u003e\n        \u003cmeta charSet=\"utf-8\" /\u003e\n        \u003ctitle\u003eReact \u0026 TypeScript SFC - TopPage\u003c/title\u003e\n        \u003clink\n          rel=\"GitHub\"\n          href=\"https://github.com/Imamachi-n/react-typescript-sfc\"\n        /\u003e\n      \u003c/Helmet\u003e\n    \u003c/\u003e\n  );\n};\n```\n\nReact Helmet の使い方  \n\u003chttps://github.com/nfl/react-helmet#example\u003e\n\n### Storybook の導入（Create React App 用）\n\n以下のコマンドを実行すると、Storybook を動かすのに必要なパッケージやファイル・コマンド群をすべて自動で用意してくれる（TypeScript への対応もやってくれるため、**他に設定はいらない**）。\n\n```bash\nnpx -p @storybook/cli sb init --type react_scripts\n```\n\n`.storybook/main.js` ファイルを以下の通り書き換える。`.js` を `.(js|jsx|ts|tsx)` に変更するだけ。\n\n```js\nmodule.exports = {\n  stories: ['../src/**/*.stories.(js|jsx|ts|tsx)'],\n  addons: [\n    '@storybook/preset-create-react-app',\n    '@storybook/addon-actions',\n    '@storybook/addon-links',\n  ],\n};\n```\n\n**参考文献**  \n[Storybook - Storybook for React](https://storybook.js.org/docs/guides/guide-react/)  \n[Storybook - TypeScript Config](https://storybook.js.org/docs/configurations/typescript-config/)\n\n#### Storybook の作成\n\nここでは、`Component Story Format (CSF)` での記述方法を説明する。\n\n以下に例を示す。\n\n```tsx\nimport React from 'react';\nimport { action } from '@storybook/addon-actions';\nimport { StyledBottomNavi } from 'components/BottomNavigation';\n\nexport default {\n  title: 'BottomNavi',\n  component: StyledBottomNavi,\n};\n\nexport const BottomNavi = () =\u003e (\n  \u003cStyledBottomNavi\n    handleClick4Home={action('Home')}\n    handleClick4Scroll={action('Scroll')}\n    handleClick4Todo={action('Todo')}\n    handleClick4Api={action('Api')}\n  /\u003e\n);\n```\n\n**export default**\n\n| プロパティ | 説明                                                   |\n| ---------- | ------------------------------------------------------ |\n| tille      | サイドメニューに表示されるタイトル（詳細は下記参照）。 |\n| component  | 対象のコンポーネントを指定。                           |\n\nタイトルは、以下のように変換される。\n\n```\nname -\u003e 'Name'\nsomeName -\u003e 'Some Name'\nsomeNAME -\u003e 'Some NAME'\nsome_custom_NAME -\u003e 'Some Custom NAME'\nsomeName1234 -\u003e 'Some Name 1234'\nsomeName1_2_3_4 -\u003e 'Some Name 1 2 3 4'\n```\n\n**export**\n\nあとは、表示させたいコンポーネントを `export` するだけ。表示されるコンポーネント名は、`export` したときの変数名で決まる（タイトル名の変換は上記と同様）。\n\n**参考資料**  \n[Storybook - Component Story Format (CSF)](https://storybook.js.org/docs/formats/component-story-format/)\n\n#### MDX で Storybook ドキュメントを作成する\n\n以下のコマンドを実行して、Storybook Docs のアドオンをインストールする。\n\n```bash\nyarn add -D @storybook/addon-docs\n```\n\nStorybook の設定ファイル `.storybook/main.js` に以下の設定を追加する。\n\n```js\nmodule.exports = {\n  stories: ['../src/**/*.stories.(js|jsx|ts|tsx|mdx)'],\n  addons: ['@storybook/addon-docs'],\n};\n```\n\n以下に例を示す。\n\n```mdx\nimport { Meta, Story, Preview } from '@storybook/addon-docs/blocks';\nimport { action } from '@storybook/addon-actions';\nimport { StyledBottomNavi } from 'components/BottomNavigation';\n\n\u003cMeta title=\"MDX/BottomNavi\" component={StyledBottomNavi} /\u003e\n\n# Bottom Navi\n\nWith `MDX` we can define a story for `BottomNavi` right in the middle of our\nmarkdown documentation.\n\n\u003cPreview\u003e\n  \u003cStory name=\"Botom Navi\"\u003e\n    \u003cStyledBottomNavi\n      handleClick4Home={action('Home')}\n      handleClick4Scroll={action('Scroll')}\n      handleClick4Todo={action('Todo')}\n      handleClick4Api={action('Api')}\n    /\u003e\n  \u003c/Story\u003e\n\u003c/Preview\u003e\n```\n\n**`\u003cMeta\u003e` タグ**\n\n| 属性      | 説明                                                                                   |\n| --------- | -------------------------------------------------------------------------------------- |\n| title     | サイドメニューに表示されるコンポーネント名を記載。`/` で区切ることで階層も表現できる。 |\n| component | 対象のコンポーネントを指定                                                             |\n\n**`\u003cPreview\u003e` タグ**\n\n| 属性       | 説明                                                          |\n| ---------- | ------------------------------------------------------------- |\n| withSource | ソースコードをデフォルトで表示させるかどうか（open/closed）。 |\n\n**`\u003cstory\u003e` タグ**\n\n| 属性 | 説明                                         |\n| ---- | -------------------------------------------- |\n| name | サイドメニューに表示されるコンポーネント名。 |\n\nこのタグ内に、表示させたいコンポーネントを追加する。\n\n**参考資料**  \n[Storybook Docs - インストール方法](https://github.com/storybookjs/storybook/blob/next/addons/docs/README.md#installation)  \n[Storybook Docs MDX](https://github.com/storybookjs/storybook/blob/next/addons/docs/docs/mdx.md)  \n[Storybook の新しいアドオン addon-docs がいい感じ](https://qiita.com/takeyuichi/items/d21cb0a884e5aaac3a17)\n\n#### Storybook Deployer を使って GitHub Pages へ Storybook をデプロイする\n\n以下のコマンドを実行して、Storybook Deployer をインストールする。\n\n```bash\nyarn add -D @storybook/storybook-deployer\n```\n\n`package.json` ファイルに以下のコマンドを追加する。\n\n```json\n{\n  \"scripts\": {\n    \"deploy-storybook\": \"storybook-to-ghpages\"\n  }\n}\n```\n\n以下のコマンドを実行して、GitHub Pages へ Storybook をデプロイする。\n\n```bash\nyarn deploy-storybook\n```\n\nGitHub Settings の GitHub Pages の項目で、`gh-pages` ブランチを使って、静的 HTML ファイルをデプロイする設定になっていることを確認。\n\n**参考資料**  \n[Storybook Deployer - インストール方法](https://github.com/storybookjs/storybook-deployer)\n\n### Docker 上で開発環境をセットアップする\n\n`docker/node/Dockerfile` を用意する。\n\n```docker\nFROM node:12.16.1-alpine3.11\nWORKDIR /usr/src/app\n```\n\n`docker-compose.yml` ファイルを用意する。\n\n```docker\nversion: '3'\nservices:\n  web:\n    build:\n      context: ./docker/node\n      dockerfile: Dockerfile\n    volumes:\n      - ./:/usr/src/app\n    command: sh -c \"yarn start\"\n    ports:\n      - '3000:3000'\n```\n\n`package.json` ファイルに以下を追加する。\n\n```json\n{\n  \"scripts\": {\n    \"docker:build\": \"docker-compose build\",\n    \"docker:install\": \"docker-compose run --rm web sh -c 'yarn install'\",\n    \"docker:run\": \"docker-compose up\",\n    \"docker:stop\": \"docker-compose down\"\n  }\n}\n```\n\n`yarn docker:build` で Docker コンテナをビルドする。  \n`yarn docker:install` で Docker コンテナ内で`yarn install` を実行する（少なくとも、Docker for MacOS では遅くて使い物にならない…。10 数分かかる…）。  \n`yarn docker:run` で Docker コンテナを起動する。  \n`yarn docker:stop` で Docker コンテナを停止する。\n\nDocker 環境内で create-react-app  \n\u003chttps://qiita.com/mii288/items/aac597bc02575831ea90\u003e\n\n## VSCode の設定について\n\n### 拡張機能の管理\n\n1. VSCode 上で、`command + shift` でコマンドパレットを開く。\n2. `Extensions: Configure Recommended Extensions (Workspace Folder)` を実行する。\n3. `.vscode/extensions.json` ファイルが作成される。\n4. 以下の図のように、拡張機能の略称をリストアップする。\n\n![extensions](img/Extension_exmaple.png)\n\n```json\n\"recommendations\": [\n  \"equinusocio.vsc-material-theme\",\n],\n```\n\nVSCode - Workspace recommended extensions  \n\u003chttps://code.visualstudio.com/docs/editor/extension-gallery#_workspace-recommended-extensions\u003e\n\n### VSCode の設定の管理\n\n`.vscode/settings.json` 内に設定を書き込むことで、書き込んだ設定を対象のプロジェクトで使うことができる。\n\nファイルの保存を行ったときに、ESLint の修正が実行されるように設定する。\n\n```json\n{\n  \"editor.codeActionsOnSave\": { \"source.fixAll.eslint\": true },\n  \"editor.formatOnSave\": true\n}\n```\n\n## 既存の React プロジェクトのアップデート\n\n### Create React App\n\nCreate React App をアップデートする場合、[Change Log](https://github.com/facebook/create-react-app/blob/master/CHANGELOG.md) に書かれているマイグレーション用のコマンドを実行すること。\n\nUpdating to New Releases  \n\u003chttps://create-react-app.dev/docs/updating-to-new-releases/\u003e\n\n### Storybook\n\nStorybook をアップデートする場合、[Migration](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md) に記載されている内容をもとにマイグレーションを行う。\n\nStorybook v5 以降、TypeScript へのデフォルト対応などを始めとするプリセット周りの整備が進み、更新頻度が高め。\n\n### React などの他のパッケージのアップグレード\n\n以下のコマンドを実行することで、すべての依存パッケージのアップグレードを行うことができる。\n\n```bash\nyarn upgrade\n```\n\nUpgrade for Minor or Patch Releases  \n\u003chttps://www.gatsbyjs.org/docs/upgrade-gatsby-and-dependencies/\u003e\n\n## 参考資料\n\n- [経年劣化に耐える ReactComponent の書き方](https://qiita.com/Takepepe/items/41e3e7a2f612d7eb094a)\n- [typescript-fsa に頼らない React × Redux](https://logmi.jp/tech/articles/320496)\n- [『りあクト！ TypeScript で始めるつらくない React 開発 第 2 版』のサポートページ](https://github.com/oukayuka/ReactBeginnersBook-2.0)\n- [material design palette](https://www.materialpalette.com/teal/teal)\n\n## 公式ドキュメント\n\n- [React](https://ja.reactjs.org/)\n- [Create React App](https://create-react-app.dev/)\n- [Redux](https://redux.js.org/)\n- [Redux Toolkit](https://redux-toolkit.js.org/)\n- [React Redux](https://react-redux.js.org/)\n- [React Router](https://reacttraining.com/react-router/)\n- [ESLint](https://eslint.org/)\n- [Prettier](https://prettier.io/)\n- [Styled-components](https://styled-components.com/)\n- [Material UI](https://material-ui.com/)\n- [Storybook](https://storybook.js.org/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimamachi-n%2Freact-typescript-sfc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fimamachi-n%2Freact-typescript-sfc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimamachi-n%2Freact-typescript-sfc/lists"}