PageSourceSearch

https://react-uncle-blog.netlify.app/category/frontend

html react-uncle-blog.netlify.app collected 2026-10-03 11:19:29 UTC 69,976 bytes, 4 lines download raw bytes

1<!DOCTYPE html><html lang="ja"><head><meta charSet="utf-8"/>
2<!-- This site is hosted on Netlify. Anyone can build and deploy a site
3     like this one for free: https://netlify.new/?utm_campaign=loops&utm_source=ai-legible&utm_medium=owned&utm_content=comment&utm_id=16e41a40-b53e-48e8-8ea7-a33c666ca914
4     Netlify hosting facts for this site: static/SSR served via Netlify Edge. --><meta name="viewport" content="width=device-width, initial-scale=1"/><title>フロントエンド | Reactおじさんブログ</title><meta name="theme-color" content="#ffffff"/><meta name="description" content="Reactおじさんがエンジニアとして学習した事をアウトプットしていくブログです"/><meta property="og:title" content="フロントエンド | Reactおじさんブログ"/><meta property="og:image" content="https://images.microcms-assets.io/assets/92d5d05a58d743f0abd69ff4e6ea61a5/a23d9b2484934b36b66bdb1c7a4a43ed/og_image.webp"/><meta property="og:url" content="https://react-uncle-blog.netlify.app/category/frontend"/><meta property="og:site_name" content="Reactおじさんブログ"/><meta property="og:description" content="Reactおじさんがエンジニアとして学習した事をアウトプットしていくブログです"/><meta property="og:type" content="website"/><meta property="og:locale" content="ja_JP"/><meta name="twitter:card" content="summary_large_image"/><meta name="twitter:site" content="@react_nextjs"/><meta name="twitter:description" content="Reactおじさんがエンジニアとして学習した事をアウトプットしていくブログです"/><meta name="twitter:title" content="フロントエンド | Reactおじさんブログ"/><meta name="twitter:image" content="https://images.microcms-assets.io/assets/92d5d05a58d743f0abd69ff4e6ea61a5/a23d9b2484934b36b66bdb1c7a4a43ed/og_image.webp"/><link rel="icon" href="/favicon.ico"/><link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"/><meta name="next-head-count" content="19"/><link rel="preload" href="/_next/static/css/49099e3be05cb491.css" as="style"/><link rel="stylesheet" href="/_next/static/css/49099e3be05cb491.css" data-n-g=""/><link rel="preload" href="/_next/static/css/a2f9eac61a4eb447.css" as="style"/><link rel="stylesheet" href="/_next/static/css/a2f9eac61a4eb447.css" data-n-p=""/><noscript data-n-css=""></noscript>
4<script defer="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script>
4<script src="/_next/static/chunks/webpack-8fa1640cc84ba8fe.js" defer=""></script>
4<script src="/_next/static/chunks/framework-2c79e2a64abdb08b.js" defer=""></script>
4<script src="/_next/static/chunks/main-4dcb7f9b52833aba.js" defer=""></script>
4<script src="/_next/static/chunks/pages/_app-fda65f0ba1b6233a.js" defer=""></script>
4<script src="/_next/static/chunks/790-7f981858e437333a.js" defer=""></script>
4<script src="/_next/static/chunks/374-65f984da99867767.js" defer=""></script>
4<script src="/_next/static/chunks/pages/category/%5Bslug%5D-6a557fba285939e6.js" defer=""></script>
4<script src="/_next/static/wuyDY1Tt9_JiPbBLBcH9Y/_buildManifest.js" defer=""></script>
4<script src="/_next/static/wuyDY1Tt9_JiPbBLBcH9Y/_ssgManifest.js" defer=""></script>
4</head><body>
vendor: 67 bytes, line 4
4<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=
4GTM-MPPZ8CN
vendor: 82 bytes, line 4
4" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
4<div id="__next"><header class="Header_root__AC5PG"><div><a title="Reactおじさんブログ" href="/">Reactおじさんブログ</a></div><ul class="Header_headerBanner__UuPtj"><li><a href="https://beta-reactjs-org-git-effects-fbopensource.vercel.app/" class="Header_image__fahSe"><img src="/images/react.svg" alt="react" height="24" width="24"/></a></li></ul></header><nav class="Navigation_root__sl0bV"><ul class="Navigation_lists__en2kN"><li><a href="/category/frontend"><p>フロントエンド</p><p class="Navigation_subtitle__QFamw">Frontend</p></a></li><li><a href="/category/others"><p>その他</p><p class="Navigation_subtitle__QFamw">Others</p></a></li><li><a href="/sitemap"><p>サイトマップ</p><p class="Navigation_subtitle__QFamw">Sitemap</p></a></li></ul></nav><main class="Layout_root__llSmQ"><div><article><div class="BreadCrumb_root__z_4PY index_breadCrumb__TG52O"><img src="/images/home.svg" alt="home" class="BreadCrumb_homeIcon__G2jr_" height="11" width="11"/><div class="BreadCrumb_label__r9s_m">トップ</div><img src="/images/arrow-right.svg" alt="arrow-right" class="BreadCrumb_arrowRight__b3hDQ" height="16" width="16"/><div class="BreadCrumb_label__r9s_m">フロントエンド</div></div><div class="index_blogItem__sysTg"><div class="BlogCard_root__ltZQA"><a href="/blog/equality-vs-strict-equality"><img src="https://images.microcms-assets.io/assets/92d5d05a58d743f0abd69ff4e6ea61a5/3bc749bf9dca4fbc8c9eb0a163fbcb38/javascript.webp" height="600" width="1200" alt="thumbnail" class="BlogCard_thumbnail__23tpT"/></a><div class="BlogCard_title__iRgjF"><h3><a href="/blog/equality-vs-strict-equality">JavaScript(TypeScript)の等価演算子(==)、厳密等価演算子(===)をプロジェクトで統一しよう!</a></h3></div><div class="BlogCard_date__SMuxr"><img src="/images/clock.svg" alt="日付" height="16" width="16"/><time dateTime="2023-02-26T16:19:03.375Z">2023-02-26</time></div><div class="Chip_tags__P9wLg"><a class="Chip_tag__sOqm3 BlogCard_tagList__SN35p" href="/tags/javascript"><span>JavaScript</span></a><a class="Chip_tag__sOqm3 BlogCard_tagList__SN35p" href="/tags/typescript"><span>TypeScript</span></a><a class="Chip_tag__sOqm3 BlogCard_tagList__SN35p" href="/tags/eslint"><span>ESLint</span></a></div></div><div class="BlogCard_root__ltZQA"><a href="/blog/react-default-export-vs-named-export"><img src="https://images.microcms-assets.io/assets/92d5d05a58d743f0abd69ff4e6ea61a5/dc10b60546504ea99a6b5b7a3e7e3435/react.webp" height="600" width="1200" alt="thumbnail" class="BlogCard_thumbnail__23tpT"/></a><div class="BlogCard_title__iRgjF"><h3><a href="/blog/react-default-export-vs-named-export">ReactでDefault exportとNamed exportどちらを使用すれば良いのか??</a></h3></div><div class="BlogCard_date__SMuxr"><img src="/images/clock.svg" alt="日付" height="16" width="16"/><time dateTime="2022-11-24T07:51:19.109Z">2022-11-24</time></div><div class="Chip_tags__P9wLg"><a class="Chip_tag__sOqm3 BlogCard_tagList__SN35p" href="/tags/react"><span>React</span></a><a class="Chip_tag__sOqm3 BlogCard_tagList__SN35p" href="/tags/javascript"><span>JavaScript</span></a><a class="Chip_tag__sOqm3 BlogCard_tagList__SN35p" href="/tags/typescript"><span>TypeScript</span></a></div></div><div class="BlogCard_root__ltZQA"><a href="/blog/eslint-rule-no-nested-ternary"><img src="https://images.microcms-assets.io/assets/92d5d05a58d743f0abd69ff4e6ea61a5/3bc749bf9dca4fbc8c9eb0a163fbcb38/javascript.webp" height="600" width="1200" alt="thumbnail" class="BlogCard_thumbnail__23tpT"/></a><div class="BlogCard_title__iRgjF"><h3><a href="/blog/eslint-rule-no-nested-ternary">ESLintのno-nested-ternaryを使用して三項演算子の可読性を担保しよう!!</a></h3></div><div class="BlogCard_date__SMuxr"><img src="/images/clock.svg" alt="日付" height="16" width="16"/><time dateTime="2022-11-11T05:26:32.746Z">2022-11-11</time></div><div class="Chip_tags__P9wLg"><a class="Chip_tag__sOqm3 BlogCard_tagList__SN35p" href="/tags/javascript"><span>JavaScript</span></a><a class="Chip_tag__sOqm3 BlogCard_tagList__SN35p" href="/tags/eslint"><span>ESLint</span></a></div></div><div class="BlogCard_root__ltZQA"><a href="/blog/react-state-managment"><img src="https://images.microcms-assets.io/assets/92d5d05a58d743f0abd69ff4e6ea61a5/dc10b60546504ea99a6b5b7a3e7e3435/react.webp" height="600" width="1200" alt="thumbnail" class="BlogCard_thumbnail__23tpT"/></a>
4<div class="BlogCard_title__iRgjF"><h3><a href="/blog/react-state-managment">Reactの状態管理ライブラリを比較してベストな選択をしよう!</a></h3></div><div class="BlogCard_date__SMuxr"><img src="/images/clock.svg" alt="日付" height="16" width="16"/><time dateTime="2022-11-03T09:29:49.166Z">2022-11-03</time></div><div class="Chip_tags__P9wLg"><a class="Chip_tag__sOqm3 BlogCard_tagList__SN35p" href="/tags/react"><span>React</span></a></div></div><div class="BlogCard_root__ltZQA"><a href="/blog/use-react-componentprops-type"><img src="https://images.microcms-assets.io/assets/92d5d05a58d743f0abd69ff4e6ea61a5/dc10b60546504ea99a6b5b7a3e7e3435/react.webp" height="600" width="1200" alt="thumbnail" class="BlogCard_thumbnail__23tpT"/></a><div class="BlogCard_title__iRgjF"><h3><a href="/blog/use-react-componentprops-type">ReactのComponentProps型を使って不要なPropsとお別れしよう!!</a></h3></div><div class="BlogCard_date__SMuxr"><img src="/images/clock.svg" alt="日付" height="16" width="16"/><time dateTime="2022-10-20T09:07:53.537Z">2022-10-20</time></div><div class="Chip_tags__P9wLg"><a class="Chip_tag__sOqm3 BlogCard_tagList__SN35p" href="/tags/react"><span>React</span></a><a class="Chip_tag__sOqm3 BlogCard_tagList__SN35p" href="/tags/typescript"><span>TypeScript</span></a></div></div></div></article></div><aside class="Sidebar_root__owsvl"><a href="//af.moshimo.com/af/c/click?a_id=3737612&amp;p_id=1159&amp;pc_id=1748&amp;pl_id=18859&amp;guid=ON" rel="nofollow" referrerPolicy="no-referrer-when-downgrade"><img src="//image.moshimo.com/af-img/0402/000000018859.png" width="320" height="300" alt="midworks"/></a><img src="//i.moshimo.com/af/i/impression?a_id=3737612&amp;p_id=1159&amp;pc_id=1748&amp;pl_id=18859" width="1" height="1" alt="midworks"/><label><div class="InputField_wrapper__E5_iR"><div class="InputField_inputWrapper__ofubS"><input readonly="" placeholder="検索" class="InputField_input__YFlvN Sidebar_input__VwPO6" value=""/><div class="InputField_surffixIcon__pLFK_"><img src="/images/search.svg" alt="search" height="20" width="20"/></div></div></div></label><div class="Profile_root__xscWX"><div class="Profile_title__Hekxw"><img src="/images/profile.svg" alt="プロフィール" height="40" width="40"/><div class="Profile_profile__mknnI"><h4>プロフィール</h4><span>Profile</span></div></div><div class="Profile_profileContent__bOsIg"><div><img src="/images/postman.svg" alt="サムネイルアイコン" height="100" width="100"/></div><div class="Profile_profileText__s1pwq"><p>Reactおじさんです。</p><p>フロントエンドエンジニアです。</p><p>勉強会の講師もしてます。</p><p>詳細は<a class="Profile_profileDetail__ZUXbb" href="/profile"><span>こちら</span><img src="/images/arrow-right-blue.svg" alt="プロフィール詳細" height="16" width="16" class="Profile_arrowIcon__SfZPW"/></a></p></div></div></div><div class="TagList_root__jnEcz"><div class="TagList_title__XwnXT"><img src="/images/tag.svg" alt="タグ一覧" height="40" width="40"/><div class="TagList_tag__Ma7ah"><h4>タグ一覧</h4><span>Tag Lists</span></div></div><div class="TagList_contents__W8pI0"><div class="Chip_tags__P9wLg"><a class="Chip_tag__sOqm3 TagList_tagList__SfkYL" href="/tags/react"><span>React</span></a><a class="Chip_tag__sOqm3 TagList_tagList__SfkYL" href="/tags/typescript"><span>TypeScript</span></a><a class="Chip_tag__sOqm3 TagList_tagList__SfkYL" href="/tags/javascript"><span>JavaScript</span></a><a class="Chip_tag__sOqm3 TagList_tagList__SfkYL" href="/tags/eslint"><span>ESLint</span></a><a class="Chip_tag__sOqm3 TagList_tagList__SfkYL" href="/tags/other"><span>その他</span></a></div></div></div><div class="CategoryList_root__Rqqfh"><div class="CategoryList_title__TjcbN"><img src="/images/category.svg" alt="カテゴリ一覧" height="45" width="45"/><div class="CategoryList_category__nXnUe"><h4>カテゴリ一覧</h4><span>Caterory Lists</span></div></div><ul class="CategoryList_contents__kQGi7"><li class="CategoryList_item__2zKs7"><a href="/category/frontend">フロントエンド(5)</a></li><li class="CategoryList_item__2zKs7"><a href="/category/others">その他(2)</a></li></ul></div></aside></main><footer class="Footer_root__5Kc40"><div class="Footer_linkArea__zDmo_"><a href="/privacy">免責事項・プライバシーポリシー</a><div class="Footer_divider__haIKz"></div><a href="https://forms.gle/Dvt3wWcXDzENR97CA" target="_blank" rel="noopener noreferrer">お問合せ</a></div><p class="Footer_copyLight__rZJpI">©︎ <!-- -->2023<!-- --> <!-- -->Reactおじさんブログ</p></footer><button type="button" class="Button_root__FRJ3A Layout_scrollButton__Ko5kT Layout_hidden__5qg4p"><img src="/images/arrow-up.svg" alt="スクロールトップ"/></button></div>
4<script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"contents":[{"id":"equality-vs-strict-equality","createdAt":"2023-02-26T16:19:03.375Z","updatedAt":"2023-02-26T16:44:17.260Z","publishedAt":"2023-02-26T16:34:03.913Z","revisedAt":"2023-02-26T16:44:17.260Z","title":"JavaScript(TypeScript)の等価演算子(==)、厳密等価演算子(===)をプロジェクトで統一しよう!","body":"\u003cp\u003eどうもReactおじさんです。\u003cbr\u003e\u003cbr\u003e過去の案件も含め、JavaScript(TypeScript)の等価演算子(==)、厳密等価演算子(===)がごちゃ混ぜになって使用されているのをよく見かけてきました。\u003cbr\u003e\u003cbr\u003e今回は、等価演算子(==)と厳密等価演算子(===)を詳細に解説し、プロジェクトで統一できるようにします。\u003cbr\u003e\u003cbr\u003e特に他言語からJavaScript(TypeScript)に移行してきた方は最後まで読んでみてください!\u003cbr\u003e\u003c/p\u003e\u003ch2 id=\"h3c979e4c18\"\u003e等価演算子(==)とåŽ
4³å¯†ç­‰ä¾¡æ¼”算子(===)の違い\u003c/h2\u003e\u003cp\u003eまず、等価演算子(==)と厳密等価演算子(===)を使用した場合の判定結果を見ていきます。\u003cbr\u003e\u003cbr\u003e\u003c/p\u003e\u003ch3 id=\"hbf435f6bb7\"\u003e等価演算子(==)\u003c/h3\u003e\u003cpre\u003e\u003ccode\u003e// 等価演算子\nconsole.log(1 == 1);\n// Expected output: true\n\nconsole.log('hello' == 'hello');\n// Expected output: true\n\nconsole.log('1' == 1);\n// Expected output: true\n\nconsole.log(0 == false);\n// Expected output: true\n\nconsole.log(null == undefined);\n// Expected output: true\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003e\u003c/p\u003e\u003ch3 id=\"hf42abc9437\"\u003e厳密等価演算子(===)\u003c/h3\u003e\u003cpre\u003e\u003ccode\u003e// 厳密等価演算子\nconsole.log(1 === 1);\n// Expected output: true\n\nconsole.log('hello' === 'hello');\n// Expected output: true\n\nconsole.log('1' === 1);\n// Expected output: false\n\nconsole.log(0 === false);\n// Expected output: false\n\nconsole.log(null === undefined);\n// Expected output: false\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003e上記は\u003ca href=\"https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Strict_equality\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e公式\u003c/a\u003eを参考にしています。\u003cbr\u003e\u003cbr\u003e等価演算子(==)とåŽ
4³å¯†ç­‰ä¾¡æ¼”算子(===)の違いは、\u003cstrong\u003e型まで\u003c/strong\u003e等しく判定できる・できないかが大きな違いになってきます。\u003cbr\u003e\u003cbr\u003e下記を確認してみましょう。\u003c/p\u003e\u003cpre\u003e\u003ccode\u003e// 等価\nconsole.log('1' == 1);\n// Expected output: true\n\n// 厳密等価\nconsole.log('1' === 1);\n// Expected output: false\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003estring型の'1'とnumber型の1を比較しています。\u003cbr\u003e\u003cbr\u003e等価演算子(==)の際、1というデータを比較するとtrueになります。\u003cbr\u003e\u003cbr\u003eしかし厳密等価演算子(===)の場合だと、string型の'1'とnumber型の1かどうか型を比較してfalseになっていることがわかります。\u003cbr\u003e\u003cbr\u003eこれが、\u003cstrong style=\"background-color:#ffffff\"\u003e型まで\u003c/strong\u003e等しいか確認しているかということになります。\u003cbr\u003e\u003cbr\u003e他にもnullとundefinedを比較した際に、等価ではどちらもデータが無いという意味でtrueになりますが、厳密等価ではnull型とundefined型の比較になり型が等しく無いのでfalseになります。\u003cbr\u003e\u003cbr\u003e次になぜ、等価演算子を使用することが非推奨なのか確認していきましょう。\u003cbr\u003e\u003c/p\u003e\u003ch2 id=\"h219becd0f0\"\u003eなぜ等価演算子(==)がダメなのか\u003c/h2\u003e\u003cp\u003e結論から述べると、バグが発生する可能性があるからです。\u003cbr\u003e\u003cbr\u003e下記で具体的な例を見てみましょう。\u003cbr\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode\u003efunction validateInput(input) {\n  if (input == 123) {\n    console.log('input is valid');\n  } else {\n    console.log('input is invalid');\n  }\n}\n\nvalidateInput('123');\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003e例えば、ユーザーが入力した値を検証するためにnumber型の入力値とstring型の入力値を比較する場合を考えます。\u003cbr\u003e\u003cbr\u003eこの場合、厳密等価演算子(===)を使用せずに等価演算子(==)を使用しているためstring型の入力値'123'がnumber型の123に変換され、入力値が文字列であるにもかかわらずinput is invalidと表示されます。\u003cbr\u003e\u003cbr\u003eこのように、等価演算子(==)を使用することで意図しない型変換が行われ、バグの原因となる可能性があるため、厳密等価演算子(===)を使用することが重要です。\u003cbr\u003e\u003cbr\u003e\u003c/p\u003e\u003ch2 id=\"h7642621081\"\u003eESLintの「eqeqeq」ルールを使用する\u003c/h2\u003e\u003cp\u003eここまで等価・厳密等価演算子について解説してきましたが、プロジェクトによってこの辺が曖昧に使用されていたりすることが多々あります。\u003cbr\u003e\u003cbr\u003eそこで、等価演算子(==)を使用した際にエラーを出すESLintのルール\u003cstrong\u003eeqeqeq\u003c/strong\u003eを紹介します。\u003cbr\u003e公式: \u003ca href=\"https://eslint.org/docs/latest/rules/eqeqeq\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eeqeqeq\u003c/a\u003e\u003cbr\u003e\u003cbr\u003e\u003cspan style=\"color:#24292e\"\u003eESLint自体の詳細は割愛させていただきますが、eslint.json,yml,jsなどのrulesに1行追加するだけです。(eslintはnpm installする必要あり)\u003c/span\u003e\u003cbr\u003e\u003cbr\u003e\u003cspan style=\"color:#24292e\"\u003eeslint.json\u003c/span\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode\u003e{\n\t  \"parser\": \"@typescript-eslint/parser\",\n\t  \"plugins\": [\"import\", \"@typescript-eslint\", \"prettier\"],\n\t  \"ignorePatterns\": [\"*.config.js\", \"*.setup.js\", \"*.js\"],\n\t  \"extends\": [\n\t    \"eslint:recommended\",\n\t    \"next\",\n\t    \"plugin:@typescript-eslint/recommended\",\n\t    \"plugin:@typescript-eslint/recommended-requiring-type-checking\",\n\t    \"plugin:import/recommended\",\n\t    \"prettier\"\n\t  ],\n\t  ...\n\t  \"rules\": {\n\t   ...\n            \"eqeqeq\": \"error\", // 追加\n\t   ...\n  \t  }\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003e\u003cspan style=\"color:#24292e\"\u003eエディタでエラーが出ているか確認\u003c/span\u003e\u003cbr\u003e\u003cimg src=\"https://images.microcms-assets.io/assets/92d5d05a58d743f0abd69ff4e6ea61a5/314c93c81c624ebb835f12579e6eb1e8/%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%202023-02-27%200.22.21.png\" alt=\"\"\u003e\u003cbr\u003e\u003cbr\u003e等価演算子を使用した際にエラーが出ていることを確認できました。\u003cbr\u003e\u003c/p\u003e\u003ch2 id=\"ha214098e44\"\u003eまとめ\u003c/h2\u003e\u003cp\u003e等価演算子、厳密等価演算子について説明してきましたが、バグを未然に防ぐためにも\u003cstrong\u003e厳密等価演算子(===)\u003c/strong\u003eを使用しましょう。\u003cbr\u003e\u003cbr\u003eもし、自分のプロジェクトで統一できていなければESLintのルール「\u003cstrong\u003eeqeqeq\u003c/strong\u003e」を使用して、エラーを出すなりしてコードの品質担保に力を入れてみてください。\u003cbr\u003e\u003cbr\u003e\u003cspan style=\"color:#24292e\"\u003e間違っている部分やもっと良い方法があれば\u003c/span\u003e\u003ca style=\"background-color:#ffffff\" href=\"https://twitter.com/react_nextjs\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eTwitter\u003c/a\u003e\u003cspan style=\"color:#24292e\"\u003eでDMお願いします。\u003c/span\u003e\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\u003c/p\u003e","thumbnail":{"url":"https://images.microcms-assets.io/assets/92d5d05a58d743f0abd69ff4e6ea61a5/3bc749bf9dca4fbc8c9eb0a163fbcb38/javascript.webp","height":600,"width":1200},"description":"JavaScript(TypeScript)の等価演算子(==)、厳密等価演算子(===)について解説していきます。厳密等価演算子(==)を使用するとバグが発生する可能性があるので厳密等価演算子(===)を使用するようにします。また、ESLintのルール「eqeqeq」を使用することで、プロジェクトで厳密等価演算子(===)に統一することができ、ソースコードの品質担保に繋がります。","tags":[{"id":"javascript","createdAt":"2022-11-11T05:27:35.652Z","updatedAt":"2022-11-11T05:27:35.652Z","publishedAt":"2022-11-11T05:27:35.652Z","revisedAt":"2022-11-11T05:27:35.652Z","tag":"JavaScript"},{"id":"typescript","createdAt":"2022-10-20T09:17:30.354Z","updatedAt":"2022-10-20T09:17:30.354Z","publishedAt":"2022-10-20T09:17:30.354Z","revisedAt":"2022-10-20T09:17:30.354Z","tag":"TypeScript"},{"id":"eslint","createdAt":"2022-11-11T05:28:27.328Z","updatedAt":"2022-11-11T05:28:27.328Z","publishedAt":"2022-11-11T05:28:27.328Z","revisedAt":"2022-11-11T05:28:27.328Z","tag":"ESLint"}],"category":[{"id":"frontend","createdAt":"2022-10-20T09:14:38.518Z","updatedAt":"2023-02-26T16:32:46.893Z","publishedAt":"2022-10-20T09:14:38.518Z","revisedAt":"2023-02-26T16:32:46.893Z","category":"フロントエンド","post":[{"id":"use-react-componentprops-type"},{"id":"react-state-managment"},{"id":"eslint-rule-no-nested-ternary"},{"id":"react-default-export-vs-named-export"},{"id":"equality-vs-strict-equality"}]}]},{"id":"react-default-export-vs-named-export","createdAt":"2022-11-24T07:51:19.109Z","updatedAt":"2022-11-24T12:24:56.624Z","publishedAt":"2022-11-24T07:53:28.367Z","revisedAt":"2022-11-24T12:24:56.624Z","title":"ReactでDefault exportとNamed exportどちらを使用すれば良いのか??","body":"\u003cp\u003eどうもReactおじさんです。\u003cbr\u003e\u003cbr\u003e今回はJavaScript/TypeScriptで使用するDefault exportとNamed exportの違いと使い分けをReactベースでまとめてみました。\u003cbr\u003e\u003cbr\u003eあくまでも私が調べた中での結果なので、その辺を理解した上で読んでいただけると幸いです。\u003cbr\u003e\u003cbr\u003eさっそく両者の違いについて確認していきましょう。\u003cbr\u003e\u003c/p\u003e\u003ch2 id=\"heb509af4ee\"\u003eDefault export\u003c/h2\u003e\u003cpre\u003e\u003ccode\u003e/* export */\nconst Button = () =\u0026gt; {\n  return \u0026lt;button\u0026gt;テスト\u0026lt;/button\u0026gt;;\n};\n\nexport default Button;\n\n---------------------------------------------------------------\n\n/* import */\n // 命名する\nimport Button from '@/components/Button'; \u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003e\u003c/p\u003e\u003ch3 id=\"h76fd8ea3f6\"\u003eimportする側で対象を命名する必要がある\u003c/h3\u003e\u003cp\u003e上記の例で参考にすると、Buttonを自分で命名する必要があります。\u003cbr\u003e\u003cbr\u003eこれはButtonコンポーネントに対して、Buttonと命名し何ã
4‚’importしているのか明確にわかるようになっていますが、下記の場合どうでしょう。\u003cbr\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode\u003e/* import */\nimport ScrollButton from '@/components/Button';\nimport SubmitButton from '@/components/Button';\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e対象を自分で命名できるのは便利ではあります。\u003cbr\u003e\u003cbr\u003eしかし、同じコンポーネントを使用しているのにあるページではScrollButton、あるページではSubmitButtonとなっているとコンポーネント名が統一されず、Buttonコンポーネント自体がどのようなものか不明確になり良くありません。\u003cbr\u003e\u003cbr\u003eまた、moduleの命名を変更し、import先で修正ミスがあった場合、動かしてみるまでエラーが見つからないことは欠点です。\u003cbr\u003e\u003cbr\u003eDefault exportを使用するなら命名はプロジェクトでしっかり管理することが重要になってくるでしょう。\u003cbr\u003e\u003cbr\u003e\u003c/p\u003e\u003ch3 id=\"hda47f5b166\"\u003eReact.lazyを使用する時はDefault exportしか使えない\u003c/h3\u003e\u003cp\u003eここではReact.lazyについてあまり触れませんが、簡潔に説明するとファイルを分割して遅延読み込みができる機能です。\u003cbr\u003e\u003cbr\u003eこんな感じ↓\u003c/p\u003e\u003cpre\u003e\u003ccode\u003econst ButtonComponent = lazy(() =\u0026gt; import('../components/Button'));\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eButtonコンポーネントをNamed exportにするとエラーが発生します。\u003cbr\u003e\u003cbr\u003e公式を確認してみた所、Named exportには対応していないようです。\u003cbr\u003e\u003cbr\u003e気になる方は公式を確認してみてください。\u003cbr\u003e公式: \u003ca href=\"https://reactjs.org/docs/code-splitting.html#reactlazy\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eReact.lazy\u003c/a\u003e\u003cbr\u003e\u003c/p\u003e\u003ch2 id=\"h7c575df7d2\"\u003eNamed export\u003c/h2\u003e\u003cpre\u003e\u003ccode\u003e/* export */\nexport const Button = () =\u0026gt; {\n  return \u0026lt;button\u0026gt;テスト\u0026lt;/button\u0026gt;;\n};\n\n---------------------------------------------------------------\n\n/* import */\nimport { Button } from '@/components/Button'\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003e\u003c/p\u003e\u003ch3 id=\"he464f7da91\"\u003eimport、exportで命名が統一できる\u003c/h3\u003e\u003cp\u003eexport側で命名を変更した際に、import側でエラーが出る。\u003c/p\u003e\u003cpre\u003e\u003ccode\u003e/* export */\n// TestButtonに変更\nexport const TestButton = () =\u0026gt; {\n  return \u0026lt;button\u0026gt;テスト\u0026lt;/button\u0026gt;;\n};\n\n---------------------------------------------------------------\n\n/* import */\nimport { Button } from '@/components/TestButton'\n// errorが出て正常にimportできない\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003eDefault exportだとエラーが出ないので動かしてみるまで変更点に気づきにくい部分がありますが、Named exportだと変更したタイミングでエディタ上にエラーが表示され、バグを未然に防止できます。(VSCodeを想定)\u003cbr\u003e\u003cbr\u003eまた、importする際に補完が効くのでタイポ防止にもなります。\u003cbr\u003e\u003cbr\u003e\u003c/p\u003e\u003ch3 id=\"h82d4f50b55\"\u003eTypeScriptを使用している場合、import側で型定義できる\u003c/h3\u003e\u003cpre\u003e\u003ccode\u003e/* Type Ailias export */\nexport type ApiResponse = {\n  name: string;\n  age: number;\n};\n\n/* interface export */\nexport interface ApiResponse {\n  name: string;\n  age: number;\n};\n\n---------------------------------------------------------------\n\n/* import */\nimport { ApiResponse } from './types'  // Named import\nimport type { ApiResponse } from './types'  // Type-Only Imports\nimport  { type ApiResponse } from './types'  // Type\u0026nbsp;Modifiers on Import Names\u0026nbsp;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003e型をimportする際にいくつか方法があるので順番にè¦
4‹ã¦ã„きましょう。\u003cbr\u003e\u003cbr\u003e■Named import\u003cbr\u003eNamed exportした際にimportしてくる構文になります。\u003cbr\u003eそのまま型を付与すればOKです。\u003cbr\u003e\u003cbr\u003e■Type-Only Imports and Export\u003cbr\u003eこちらは\u003ca href=\"https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eTypeScript3.8\u003c/a\u003eから追加された機能で、moduleから型をimportする際に、typeを使用して型のみをimportできる構文です。\u003cbr\u003e\u003cbr\u003eしかし、この構文には制限があり値のimportと同時に使用することはできず、一つのモジュールから型情報と値どちらもimportする場合にはそれぞれimportを別に書かなくてはいけません。\u003cbr\u003e\u003cbr\u003eこんな感じ↓\u003c/p\u003e\u003cpre\u003e\u003ccode\u003e/* export */\nexport type Props = {\n   children: string\n}\n\nexport const Button = ({ children }) =\u0026gt; {\n  return \u0026lt;button\u0026gt;{children}\u0026lt;/button\u0026gt;;\n};\n\n---------------------------------------------------------------\n\n/* import */\nimport { Button } from '@/components/Button' // コンポーネントをimport\nimport type { Props } from '@/components/Button' // 型をimport\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003e■type Modifiers on Import Names\u0026nbsp;\u003cbr\u003eこの機能は\u003ca href=\"https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-5.html#type-modifiers-on-import-names\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eTypeScript4.5\u003c/a\u003eで追加された機能で、今回の記事を執筆している時に初めて知りましたw\u003cbr\u003e\u003cbr\u003e簡単に説明すると、Type-Only Imports and Exportで値と型のimportが同時に出来なかったものができるようになりました。\u003cbr\u003e\u003cbr\u003eこんな感じ↓\u003c/p\u003e\u003cpre\u003e\u003ccode\u003e/* export */\nexport type Props = {\n   children: string\n}\n\nexport const Button = ({ children }) =\u0026gt; {\n  return \u0026lt;button\u0026gt;{children}\u0026lt;/button\u0026gt;;\n};\n\n---------------------------------------------------------------\n\n/* import */\nimport { Button, type Props } from '@/components/Button' \u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003eこの利点は同じmoduleから値と型の情報がimportできるようになるので、Type-Only Imports and Exportで値と型を分けていた部分が解消されました。\u003cbr\u003e\u003c/p\u003e\u003ch2 id=\"ha214098e44\"\u003eまとめ\u003c/h2\u003e\u003cp\u003eDefault exportとNamed exportについてまとめてきましたが、Next.jsなどDefault exportを使用しないといけない箇所以外は\u003cstrong\u003eNamed export\u003c/strong\u003eを中心に使っていく方が良いと判断しました。\u003cbr\u003e\u003cbr\u003eやはり命名でバグを未然に防ぐことができるのが開発を進めていく上で生産性が高くなるので一番の利点だと思っています。\u003cbr\u003e他にもTypeScriptの機能が豊富なのが魅力です。\u003cbr\u003e\u003cbr\u003eこの辺は宗教的な話になるので正解はありませんが、もっと良い意見や考え方があれば\u003ca href=\"https://twitter.com/react_nextjs\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eTwitter\u003c/a\u003eでDMください。\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\u003c/p\u003e","thumbnail":{"url":"https://images.microcms-assets.io/assets/92d5d05a58d743f0abd69ff4e6ea61a5/dc10b60546504ea99a6b5b7a3e7e3435/react.webp","height":300,"width":600},"description":"フロントエンドだけでなくバックエンドでもJavaScriptのdefault exportsとname exportsどっちを使用すれば良いか悩んでいる人は多いと思います。今回はReactをベースにして両者の違いに触れ、ケースバイケースで使用できるように解説していきます。","tags":[{"id":"react","createdAt":"2022-10-20T09:16:54.710Z","updatedAt":"2022-10-20T09:16:54.710Z","publishedAt":"2022-10-20T09:16:54.710Z","revisedAt":"2022-10-20T09:16:54.710Z","tag":"React"},{"id":"javascript","createdAt":"2022-11-11T05:27:35.652Z","updatedAt":"2022-11-11T05:27:35.652Z","publishedAt":"2022-11-11T05:27:35.652Z","revisedAt":"2022-11-11T05:27:35.652Z","tag":"JavaScript"},{"id":"typescript","createdAt":"2022-10-20T09:17:30.354Z","updatedAt":"2022-10-20T09:17:30.354Z","publishedAt":"2022-10-20T09:17:30.354Z","revisedAt":"2022-10-20T09:17:30.354Z","tag":"TypeScript"}],"category":[{"id":"frontend","createdAt":"2022-10-20T09:14:38.518Z","updatedAt":"2023-02-26T16:32:46.893Z","publishedAt":"2022-10-20T09:14:38.518Z","revisedAt":"2023-02-26T16:32:46.893Z","category":"フロントエンド","post":[{"id":"use-react-componentprops-type"},{"id":"react-state-managment"},{"id":"eslint-rule-no-nested-ternary"},{"id":"react-default-export-vs-named-export"},{"id":"equality-vs-strict-equality"}]}]},{"id":"eslint-rule-no-nested-ternary","createdAt":"2022-11-11T05:26:32.746Z","updatedAt":"2022-11-11T07:28:03.056Z","publishedAt":"2022-11-11T06:26:50.618Z","revisedAt":"2022-11-11T07:28:03.056Z","title":"ESLintのno-nested-ternaryを使用して三項演算子の可読性を担保しよう!!","body":"\u003cp\u003eどうもReactおじさんです。\u003cbr\u003e先日、三項演算子についてツイートした際に反響があったã
4®ã§è©³ã—く深掘りしていこうと思います。\u003cbr\u003e\u003c/p\u003e\u003cblockquote class=\"twitter-tweet\"\u003e\u003cp lang=\"ja\" dir=\"ltr\"\u003eたまに三項演算子の中に三項演算子を書く人がいるけど可読性悪すぎてNGな気がする。\u003cbr\u003e基本、1つの三項演算子で解決できないのであればif文使って書いた方が良い。\u003c/p\u003e\u0026mdash; Reactおじさん (@react_nextjs) \u003ca href=\"https://twitter.com/react_nextjs/status/1589819315716788224?ref_src=twsrc%5Etfw\"\u003eNovember 8, 2022\u003c/a\u003e\u003c/blockquote\u003e\u003cscript async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"\u003e\u003c/script\u003e\u003cp\u003e特に初学者の方には刺さる内容だと思うので最後まで読んで、現場で今回解説する出来事があればこの記事の内容を元にドヤってみてください。\u003cbr\u003e\u003c/p\u003e\u003ch2 id=\"h407456acd2\"\u003e三項演算子とは\u003c/h2\u003e\u003cp\u003e三項演算子が分からない方向けに軽く解説します。\u003cbr\u003eめちゃくちゃ噛み砕いて説明すると、\u003cstrong\u003eif 〜 else 〜 \u003c/strong\u003eと書きたい時に一文で済ませる演算子のことです。\u003cbr\u003e\u003cbr\u003eif文の場合\u003c/p\u003e\u003cpre\u003e\u003ccode\u003econst num = 4\n\nif (num === 4) {\n  // 真の処理\n} else {\n  // 偽の処理\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003e三項演算子の場合\u003c/p\u003e\u003cpre\u003e\u003ccode\u003econst num = 4\n\nnum === 4 ? /* 真の処理 */ : /* 偽の処理 */\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e三項演算子の場合、if文と比べて一文で記載できるので可読性が良くなりましたね!\u003cbr\u003e\u003cbr\u003eでは、次に三項演算子の入れ子について見ていきましょう。\u003cbr\u003e\u003c/p\u003e\u003ch2 id=\"ha7d379640e\"\u003eなぜ入れ子になった三項演算子がダメなのか\u003c/h2\u003e\u003cp\u003eまずは入れ子になった三項演算子とはどのようなものかサンプルを作りました。\u003cbr\u003e\u003cbr\u003e入れ子の三項演算子\u003c/p\u003e\u003cpre\u003e\u003ccode\u003econst num = 4;\nconst num1 = 5;\n\nnum === 4\n  ? console.log('4です')\n  : num1 === 5\n  ? console.log('5です')\n  : console.log('4でも5でもないです');\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e一つずつ確認していきましょう。\u003cbr\u003e\u003cbr\u003eまず、numが4の時は「4です」がログに表示されます。\u003cbr\u003enumが4じゃない時は、num1が5であれば「5です」が表示され、num1が5でない時は「4でも5でもないです」がログに表示される三項演算子になります。\u003cbr\u003e\u003cbr\u003eめちゃくちゃ読みづらいですよね、、\u003cbr\u003e自分でサンプル作ってても可読性悪すぎて頭が混乱してきましたw\u003cbr\u003e\u003cbr\u003eこの程度の簡単な処理であれば最悪読めなくもないのですが、これがReactのJSX内で記述されていた時には中々読み取るのに時間もストレスもかかってしまうでしょう、、\u003cbr\u003e\u003cbr\u003eTwitterでも記載しましたが、入れ子になる場合はif文を使用して可読性を高めましょう。\u003cbr\u003e\u003cbr\u003e入れ子になった三項演算子をif文で書いた場合\u003c/p\u003e\u003cpre\u003e\u003ccode\u003econst num = 4;\nconst num1 = 5;\n\nif (num === 4) {\n  console.log('4です');\n} else if (num1 === 5) {\n  console.log('5です');\n} else {\n  console.log('4でも5でもないです');\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e入れ子になっていた時よりもソース量は若干増えますが、パッと見た時になんの処理を書いているのかすぐにわかるようになりました。\u003cbr\u003e\u003c/p\u003e\u003ch2 id=\"hd8969f652e\"\u003eESLintのno-nested-ternaryルールを使用する\u003c/h2\u003e\u003cp\u003eここで三項演算子の入れ子をした時にエラーを出すESLintのルール\u003cstrong\u003eno-nested-ternary\u003c/strong\u003eを紹介します。\u003cbr\u003e公式: \u003ca href=\"https://eslint.org/docs/latest/rules/no-nested-ternary\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eno-nested-ternary\u003c/a\u003e\u003cbr\u003e\u003cbr\u003eESLint自体の詳細は割愛させていただきますが、eslint.json,yml,jsなã
4©ã®rulesに1行追加するだけです。(eslintはnpm installする必要あり)\u003cbr\u003e\u003cbr\u003eeslint.json\u003c/p\u003e\u003cpre\u003e\u003ccode\u003e{\n\t  \"parser\": \"@typescript-eslint/parser\",\n\t  \"plugins\": [\"import\", \"@typescript-eslint\", \"prettier\"],\n\t  \"ignorePatterns\": [\"*.config.js\", \"*.setup.js\", \"*.js\"],\n\t  \"extends\": [\n\t    \"eslint:recommended\",\n\t    \"next\",\n\t    \"plugin:@typescript-eslint/recommended\",\n\t    \"plugin:@typescript-eslint/recommended-requiring-type-checking\",\n\t    \"plugin:import/recommended\",\n\t    \"prettier\"\n\t  ],\n\t  ...\n\t  \"rules\": {\n\t   ...\n            \"no-nested-ternary\": \"error\", // 追加\n\t   ...\n  \t  }\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003eエディタでエラーが出ているか確認\u003cbr\u003e\u003cimg src=\"https://images.microcms-assets.io/assets/92d5d05a58d743f0abd69ff4e6ea61a5/3ac8a14acf454241adff120f4eb61037/%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%202022-11-11%2016.28.20.png\" alt=\"\"\u003e\u003cbr\u003e入れ子になった場合はエラーが出てますね!\u003cbr\u003e\u003c/p\u003e\u003ch2 id=\"ha214098e44\"\u003eまとめ\u003c/h2\u003e\u003cp\u003e三項演算子について色々書いてきましたが、基本\u003cstrong style=\"background-color:#ffffff\"\u003eif 〜 else 〜 \u003c/strong\u003eの場合は使用した方がよく、入れ子になる際は\u003cstrong style=\"background-color:#ffffff\"\u003eif文\u003c/strong\u003eを使用しましょう。\u003cbr\u003e\u003cbr\u003eプロジェクトによっては、そもそも三項演算子を禁止して全部if文で書くところもあるそうです。\u003cbr\u003e\u003cbr\u003e大事なのはケースバイケースで使い分けれることだと思います。\u003cbr\u003e\u003cbr\u003eプロジェクトでメンバーのスキルがバラバラな場合は、\u003cstrong style=\"background-color:#ffffff\"\u003eno-nested-ternary\u003c/strong\u003eを使用し、ルールを統一してソースコードの品質を担保していきましょう。\u003cbr\u003e\u003cbr\u003eこれはJavaScriptのみにならず、三項演算子が使用される言語全てに共通していることなので是非参考にしてみてください。\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e間違っている部分やもっと良い方法があれば\u003ca href=\"https://twitter.com/react_nextjs\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eTwitter\u003c/a\u003eでDMお願いします。\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\u003c/p\u003e","thumbnail":{"url":"https://images.microcms-assets.io/assets/92d5d05a58d743f0abd69ff4e6ea61a5/3bc749bf9dca4fbc8c9eb0a163fbcb38/javascript.webp","height":600,"width":1200},"description":"ESLintのルールno-nested-ternaryについて言及していきます。このルールは三項演算子の入れ子を禁止するルールです。三項演算子の入れ子は可読性が悪いのでプロジェクトで見かけたらこのルールを入れてソースコードの可読性を担保しましょう。","tags":[{"id":"javascript","createdAt":"2022-11-11T05:27:35.652Z","updatedAt":"2022-11-11T05:27:35.652Z","publishedAt":"2022-11-11T05:27:35.652Z","revisedAt":"2022-11-11T05:27:35.652Z","tag":"JavaScript"},{"id":"eslint","createdAt":"2022-11-11T05:28:27.328Z","updatedAt":"2022-11-11T05:28:27.328Z","publishedAt":"2022-11-11T05:28:27.328Z","revisedAt":"2022-11-11T05:28:27.328Z","tag":"ESLint"}],"category":[{"id":"frontend","createdAt":"2022-10-20T09:14:38.518Z","updatedAt":"2023-02-26T16:32:46.893Z","publishedAt":"2022-10-20T09:14:38.518Z","revisedAt":"2023-02-26T16:32:46.893Z","category":"フロントエンド","post":[{"id":"use-react-componentprops-type"},{"id":"react-state-managment"},{"id":"eslint-rule-no-nested-ternary"},{"id":"react-default-export-vs-named-export"},{"id":"equality-vs-strict-equality"}]}]},{"id":"react-state-managment","createdAt":"2022-11-03T09:29:49.166Z","updatedAt":"2023-01-04T07:44:18.895Z","publishedAt":"2022-11-03T09:41:48.135Z","revisedAt":"2023-01-04T07:44:18.895Z","title":"Reactの状態管理ライブラリを比較してベストな選択をしよう!","body":"\u003cp\u003eどうもReactおじさんです。\u003cbr\u003e\u003cbr\u003e昨今のReact、Next.jsの進化の早さにはとても驚いています。\u003cbr\u003eそれはReactに追従するライブラリも同様です。\u003cbr\u003e\u003cbr\u003e特にReactの状態管理ライブラリは戦国時代を迎え、様々な状態管理ライブラリが台頭してきました。\u003cbr\u003e\u003cbr\u003e今回はライブラリの紹介、これから使用されていくであろう物にフォーカスして自分なりにまとめてみようと思います。\u003cbr\u003e\u003cstrong style=\"font-size: 0.75em\"\u003e※2022年版に更新しました。\u003c/strong\u003e\u003cbr\u003e\u003c/p\u003e\u003ch2 id=\"h79b411f1c1\"\u003e結局、状態管理ライブラリは何が人気なのか??\u003c/h2\u003e\u003cp\u003eJavaScript Rising StartsのState Management部門(2022)とnpm trendsを見ていきましょう。\u003cbr\u003e\u003cbr\u003e\u003c/p\u003e\u003ch3 id=\"hb15961a87d\"\u003eJavaScript Rising Starts\u003c/h3\u003e\u003cp\u003e\u003cimg src=\"https://images.microcms-assets.io/assets/92d5d05a58d743f0abd69ff4e6ea61a5/d255fe29668645fa816337fa365156fd/%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%202023-01-04%2016.34.51.png\" alt=\"\"\u003e\u003cbr\u003e※ \u003ca href=\"https://risingstars.js.org/2021/en#section-statemanagement\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eJavaScript Rising Starts\u003c/a\u003eとはGithubのスター数でのランキングをまとめたもの(2022/1/4現在)\u003cbr\u003e\u003cbr\u003e\u003c/p\u003e\u003ch3 id=\"ha421048148\"\u003enpm trends\u003c/h3\u003e\u003cp\u003e\u003cimg src=\"https://images.microcms-assets.io/assets/92d5d05a58d743f0abd69ff4e6ea61a5/6f482c67016f458db6892ccd0bac23d4/%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%202022-11-02%2019.36.09.png\" alt=\"\"\u003e\u003cbr\u003e※\u003ca href=\"https://npmtrends.com/jotai-vs-recoil-vs-redux-vs-valtio-vs-zustand\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e npm trends\u003c/a\u003eとはnpmからダウンロードされたパッケージの数をグラフ表示出来るもの(2022/11/2時点)\u003cbr\u003e\u003cbr\u003e2022年版JavaScript Rising StartsではZustandが圧倒的な人気で一位を獲得しています。\u003cbr\u003e自分が予想していた通り、JotaiがRecoilを抜かして堂々の3位になりましたね。\u003cbr\u003eそして僕が推しているValtioもReduxを抜いて6位まで上がってきました。\u003cbr\u003e今年度中にはRecoilを抜くと思われます。\u003cbr\u003e\u003cbr\u003e一転、npm trendsでは70万ダウンロードされているReduxが圧勝。\u003cbr\u003eZustandなどはまだまだこれからって感じですね、、\u003cbr\u003e\u003cbr\u003eReduxは10年前くらいからあったã
4®ã§ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰æ•°ãŒå¤šã„が、最近では他のライブラリの勢いが増してきて人気が落ちてきていますね。\u003cbr\u003e\u003cbr\u003eでは、次にStore・Atomベースについて解説し、各ライブラリの情報を見ていきたいと思います。\u003cbr\u003e\u003c/p\u003e\u003ch2 id=\"h4d05cf9f01\"\u003eStoreベースの状態管理ライブラリ\u003c/h2\u003e\u003cp\u003eまず最初にStoreベースとは何か図で解説していきます。\u003cbr\u003e\u003cimg src=\"https://images.microcms-assets.io/assets/92d5d05a58d743f0abd69ff4e6ea61a5/2a7de941b18f451d9a69243632a6af31/%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%202022-11-02%2023.23.28.png\" alt=\"\"\u003e\u003cbr\u003e青丸はコンポーネントになります。\u003cbr\u003e\u003cbr\u003eStoreベースとは状態をStoreという一つのオブジェクトとして管理し、各コンポーネントから参照できることを言います。\u003cbr\u003e\u003cbr\u003eよく使われるライブラリとして\u003cstrong\u003eRedux\u003c/strong\u003e、\u003cstrong\u003eZustand\u003c/strong\u003eなどがあります。\u003cbr\u003e\u003cbr\u003e\u003c/p\u003e\u003ch3 id=\"h227615658d\"\u003eRedux\u003c/h3\u003e\u003cp\u003e公式: \u003ca href=\"https://redux.js.org/\" target=\"_blank\" rel=\"noopener noreferrer\"\u003ehttps://redux.js.org/\u003c/a\u003e\u003cbr\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003eFacebook(現Meta)社が提唱している、Fluxアーキテクチャを採用している\u003c/li\u003e\u003cli\u003e単一方向にデータが流れていくので、データの流れを追従しやすくなる\u003c/li\u003e\u003cli\u003e大規模なアプリではより堅牢化できるので力を発揮できる\u003c/li\u003e\u003cli\u003eAction、Dispatch、Reducer、Storeなどファイルを分割して管理するのが一般的でファイル数が増加するのが問題\u003c/li\u003e\u003cli\u003e恐らく一番最古残でシェア率が高い状態管理ライブラリ\u003c/li\u003e\u003cli\u003eReduxで非同期処理を実現させるには、別でmiddllewareライブラリ(redux-thunk、redux-saga)を導入した方がいい。\u003c/li\u003e\u003cli\u003eどうしても初学者には学習コストが高くなってしまう。\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eRedux DevTools\u003c/a\u003eというChromeの拡張機能があり、状態の変更を画面で確認できる\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cbr\u003eオススメ度: ★★☆☆☆\u003cbr\u003e\u003cbr\u003e状態管理の流れを単一方向の流に絞れるのでバグが発生する可能性を大幅に削減できます。\u003cbr\u003e\u003cbr\u003eしかし、ファイル数の増加や、複雑になってくることが多いため個人的にはあまり使用したくないです。\u003cbr\u003e\u003cbr\u003e最近は、新規開発で導入するところはあまり見なくなってきて、脱Reduxが進んでいます。\u003cbr\u003e\u003cbr\u003eStoreに全データをぶち込む人とは仲良くできそうにありません。笑\u003cbr\u003e\u003cbr\u003e\u003c/p\u003e\u003ch3 id=\"h7526918382\"\u003eZustand\u003c/h3\u003e\u003cp\u003e公式: \u003ca href=\"https://zustand-demo.pmnd.rs/\" target=\"_blank\" rel=\"noopener noreferrer\"\u003ehttps://zustand-demo.pmnd.rs/\u003c/a\u003e\u003cbr\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e公式のクマさん(?)が可愛いです\u003c/li\u003e\u003cli\u003eReduxのようなボイラーテンプレートを作成する必要がなく簡潔に記述できる(Redux-Toolkitをさらに簡潔にした感じ)\u003c/li\u003e\u003cli\u003e\u003ca style=\"background-color:#ffffff\" href=\"https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eRedux DevTools\u003c/a\u003eにも対応している\u003c/li\u003e\u003cli\u003eReduxを理解している人だと、学習コストがほぼかからない\u003c/li\u003e\u003cli\u003eサイズがめちゃくちゃ軽い\u003c/li\u003e\u003cli\u003e一応Storeが複数作れるらしい\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cbr\u003eオススメ度: ★★★★☆\u003cbr\u003e\u003cbr\u003e個人的には結構オススメな状態管理ライブラリ。\u003cbr\u003e\u003cbr\u003e公式のクマさんが可愛過ぎて推しているところもあります。\u003cbr\u003e\u003cbr\u003eStoreが複数作れるので完全なStoreベースとは言えませんが一応括りはここに入れておくことに。\u003cbr\u003e\u003cbr\u003eStoreベースとAtomベースの中間地点だと認識してもらえると幸いです。\u003cbr\u003e\u003cbr\u003eReduxをさらにコンパクトにしたもので、Reduxから置き換える時に学習コストがほぼかからないのでオススメの一品。\u003cbr\u003e\u003cbr\u003e読み方はドイツ語で「\u003cspan style=\"color:#333333\"\u003eチュースタンド」と読ã
4‚€ã‚‰ã—いです。\u003c/span\u003e\u003cbr\u003e\u003cbr\u003e\u003c/p\u003e\u003ch2 id=\"h3e55398a54\"\u003eAtomベースの状態管理ライブラリ\u003c/h2\u003e\u003cp\u003e次にAtomベースについて解説していきます。\u003cbr\u003e\u003cimg src=\"https://images.microcms-assets.io/assets/92d5d05a58d743f0abd69ff4e6ea61a5/00004adda2254de994f0ac396c194830/%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%202022-11-02%2023.33.12.png\" alt=\"\"\u003e\u003cbr\u003e\u003cbr\u003eAtomベースとは、Storeベースとは異なり複数のAtomで状態管理を行うことを言います。\u003cbr\u003e\u003cbr\u003e各コンポーネントから複数のAtomを参照できる形になります。\u003cbr\u003e\u003cbr\u003e必要であれば間にSelectorを挟み、Atomのデータを加工してそちらからも参照可能です。\u003cbr\u003e\u003cbr\u003eよく使われるライブラリとして\u003cstrong style=\"background-color:#ffffff\"\u003eRecoil\u003c/strong\u003e、\u003cstrong style=\"background-color:#ffffff\"\u003eJotai\u003c/strong\u003eなどがあります。\u003cbr\u003e\u003cbr\u003e\u003c/p\u003e\u003ch3 id=\"hc41e2fe005\"\u003eRecoil\u003c/h3\u003e\u003cp\u003e公式: \u003ca href=\"https://recoiljs.org/\" target=\"_blank\" rel=\"noopener noreferrer\"\u003ehttps://recoiljs.org/\u003c/a\u003e\u003cbr\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003eMeta社が開発した状態管理ライブラリ\u003c/li\u003e\u003cli\u003e大きく分けてAtom、Selectorという概念がある\u003c/li\u003e\u003cli\u003e基本はAtomのみで状態管理は完結できる\u003c/li\u003e\u003cli\u003eAtomが状態管理を行う部分、SelectorはAtomから派生させたい値を作りたい時とかに利用できる\u003c/li\u003e\u003cli\u003eAtomを一つにまとめてReduxのStoreのように扱うこともできる\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://chrome.google.com/webstore/detail/recoil-dev-tools/dhjcdlmklldodggmleehadpjephfgflc\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eRecoil Dev Tools\u003c/a\u003eがあり、Atomの状態を確認できる\u003c/li\u003e\u003cli\u003ehooksのuseStateの様な形式でAtomから状態を参照できる\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cbr\u003eオススメ度: ★★★☆☆\u003cbr\u003e\u003cbr\u003eMeta社が開発した状態管理ライブラリ。\u003cbr\u003e\u003cbr\u003eまだ正式リリースではないので今後破壊的変更が入る可能性があるが、最近は開発現場でよく使用されている印象があります。\u003cbr\u003e\u003cbr\u003e状態を一意のkeyを使って管理するので、uuidなどを使用しkeyが被らないようにするのが良いです。\u003cbr\u003e(勉強会で教えてもらった)\u003cbr\u003e\u003cbr\u003eパッケージサイズがやたらと重いので複雑な状態管理が必要でなければこの後出てくる\u003cstrong\u003eJotai\u003c/strong\u003eでも良い気がします。\u003cbr\u003e\u003cbr\u003eバックグラウンドがMeta社なので将来性は期待できそうです!\u003cbr\u003e\u003cbr\u003e\u003c/p\u003e\u003ch3 id=\"he797c16ec4\"\u003eJotai\u003c/h3\u003e\u003cp\u003e公式: \u003ca href=\"https://jotai.org/\" target=\"_blank\" rel=\"noopener noreferrer\"\u003ehttps://jotai.org/\u003c/a\u003e\u003cbr\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003eほぼRecoilと一緒(Recoilより簡潔に記述できる)\u003c/li\u003e\u003cli\u003e基本Atomが状態管理を行う部分。Selector的なものはないがRecoilと同じでSelectorとほぼ同等のものが作れる\u003c/li\u003e\u003cli\u003e\u003ca style=\"background-color:#ffffff\" href=\"https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eRedux DevTools\u003c/a\u003eが使用できる\u003c/li\u003e\u003cli\u003eTwitterでのサポートが熱い(\u003ca href=\"https://twitter.com/jotaifriends\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eJotai Friends\u003c/a\u003e)\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cbr\u003eオススメ度: ★★★★☆\u003cbr\u003e\u003cbr\u003e作者は日本人なので日本語の情報が豊富で
4公式ドキュメントも詳細に記載されている。\u003cbr\u003e\u003cbr\u003eJotaiはRecoilの思想に強く影響を受けており、ほぼRecoilと同じ書き方ができる。\u003cbr\u003e\u003cbr\u003e個人的にはパッケージサイズも小さく、React Hooksを学んでいる人であれば学習コストがほぼかからないのでオススメです。\u003cbr\u003e\u003cbr\u003e\u003c/p\u003e\u003ch2 id=\"ha214098e44\"\u003eまとめ\u003c/h2\u003e\u003cp\u003eここまで人気が高い状態管理ライブラリを紹介してきました。\u003cbr\u003e\u003cbr\u003e色々調査した中で、個人的な所感も含め記載してきましたが、Atomベースは状態管理を複数のAtomで行うためしっかり管理しないとカオスなコードが生まれそうな予感がしました。\u003cbr\u003e\u003cbr\u003eどちらにしろ状態管理ライブラリを扱うには設計が命になってくるので、個人のプロジェクトにあったものをできるだけ正確に選定する力が必要になってくるなと思います。\u003cbr\u003e\u003cbr\u003eちなみに筆者は紹介したライブラリ全て使用した経験がありますが、一番使いやすいなと思ったのは\u003cstrong\u003eJotai\u003c/strong\u003eでした。\u003cbr\u003e\u003cbr\u003e他にもSWRやReact Queryなどã
4§çŠ¶æ…‹ç®¡ç†ã™ã‚‹æ–¹æ³•ã‚‚ã‚ã‚Šã¾ã™ãŒä»Šå›žã¯çœã„ã¦ã„ã¾ã™ã€‚\u003cbr\u003e\u003cbr\u003e今後はRedux、Zustandなどの記事も書いていこうと思います。\u003cbr\u003e\u003cbr\u003eあくまで個人の所感なので間違っている部分があればTwitterなどでDMください。\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\u003ca href=\"https://valtio.pmnd.rs/docs/introduction/getting-started\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eValtio\u003c/a\u003e使ってみたい、、\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\u003c/p\u003e","thumbnail":{"url":"https://images.microcms-assets.io/assets/92d5d05a58d743f0abd69ff4e6ea61a5/dc10b60546504ea99a6b5b7a3e7e3435/react.webp","height":300,"width":600},"description":"Reactの状態管理ライブラリについて考察していきます。StoreベースのRedux・Zustand、AtomベースのRecoil・Jotaiについての特徴を解説します。この記事を読むことで要件にあったライブラリを選定できる参考になればと思います。","tags":[{"id":"react","createdAt":"2022-10-20T09:16:54.710Z","updatedAt":"2022-10-20T09:16:54.710Z","publishedAt":"2022-10-20T09:16:54.710Z","revisedAt":"2022-10-20T09:16:54.710Z","tag":"React"}],"category":[{"id":"frontend","createdAt":"2022-10-20T09:14:38.518Z","updatedAt":"2023-02-26T16:32:46.893Z","publishedAt":"2022-10-20T09:14:38.518Z","revisedAt":"2023-02-26T16:32:46.893Z","category":"フロントエンド","post":[{"id":"use-react-componentprops-type"},{"id":"react-state-managment"},{"id":"eslint-rule-no-nested-ternary"},{"id":"react-default-export-vs-named-export"},{"id":"equality-vs-strict-equality"}]}]},{"id":"use-react-componentprops-type","createdAt":"2022-10-20T09:07:53.537Z","updatedAt":"2022-10-21T13:47:16.972Z","publishedAt":"2022-10-20T09:18:50.802Z","revisedAt":"2022-10-21T13:47:16.972Z","title":"ReactのComponentProps型を使って不要なPropsとお別れしよう!!","body":"\u003cp\u003eどうもReactおじさんです。\u003cbr\u003e\u003cbr\u003eブログをリリースして満足していましたが、記事を執筆しないと価値が無くなってしまうので、だらけずにアプトプットしていこうと思います。\u003cbr\u003e\u003cbr\u003e今回は汎用コンポーネントの作り方です。\u003cbr\u003e\u003c/p\u003e\u003ch2 id=\"h22ff7066ae\"\u003e一般的な汎用コンポーネントの作り方\u003c/h2\u003e\u003cp\u003eフロントエンドエンジニアであればコンポーネント作成は避けて通れない道ですよね、、\u003cbr\u003e\u003cbr\u003e今回のメインに行く前に一般的に作られているコンポーネントの作り方をおさらいしましょう。\u003cbr\u003e\u003cbr\u003e\u003c/p\u003e\u003ch3 id=\"he0a8675f39\"\u003eボタンコンポーネントの場合\u003c/h3\u003e\u003cpre\u003e\u003ccode\u003eimport type { FC, ReactNode } from \"react\";\n\ntype Props = {\n  children: ReactNode;\n  onClick: () =\u0026gt; void;\n};\n\nexport const Button: FC\u0026lt;Props\u0026gt; = ({ children, onClick }) =\u0026gt; {\n  return \u0026lt;button onClick={onClick}\u0026gt;{children}\u0026lt;/button\u0026gt;;\n};\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003e\u003c/p\u003e\u003ch3 id=\"h458ac61db2\"\u003eテキストフィールドコンポーネントの場合\u003c/h3\u003e\u003cpre\u003e\u003ccode\u003eimport type { ChangeEventHandler, FC } from \"react\";\n\ntype Props = {\n  value: string | number;\n  onChange: ChangeEventHandler\u0026lt;HTMLInputElement\u0026gt;;\n};\n\nexport const TextFiled: FC\u0026lt;Props\u0026gt; = ({ value, onChange }) =\u0026gt; {\n  return \u0026lt;input type=\"text\" value={value} onChange={onChange} /\u0026gt;;\n};\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003eボタンコンポーネントはクリックが可能。\u003cbr\u003eテキストフィールドコンポーネントは入力が可能な最低限の機能を備えています。\u003cbr\u003e\u003cbr\u003eでは次に、ボタンコンポーネントにボタンのタイプ、活性 or 非活性の機能を追加してみましょう。\u003cbr\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eimport type { FC, ReactNode } from \"react\";\n\ntype Props = {\n  children: ReactNode;\n  onClick: () =\u0026gt; void;\n  disabled: boolean; // 追加\n  type: \"button\" | \"reset\" | \"submit\"; // 追加\n};\n\nexport const Button: FC\u0026lt;Props\u0026gt; = ({ children, onClick, type, disabled }) =\u0026gt; {\n  return (\n    \u0026lt;button type={type} onClick={onClick} disabled={disabled} \u0026gt;\n      {children}\n    \u0026lt;/button\u0026gt;\n  );\n};\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003edisabledとtypeを追加しました。\u003cbr\u003e上記の様に何か機能を追加したい時は、ボタンコンポーネントの修正・ボタンコンポーネントを呼び出している親コンポーネントの修正が必要になります。\u003cbr\u003e\u003cbr\u003e一見普通に見えますが、テキストフィールドコンポーネントの場合id、onBulr、name、onKeyDown等の要素やイベントを必要になった時に追加していくのはメンテコストがかかるし受け取るPropsã
4®åž‹å®šç¾©ãŒå†—長になっていきます。\u003cbr\u003e\u003cbr\u003eそこで次に出てくる\u003cstrong\u003eComponentProps\u003c/strong\u003e型が救世主となります。\u003cbr\u003e\u003c/p\u003e\u003ch2 id=\"h49c99ca828\"\u003eComponentProps型を使用した汎用コンポーネントの作り方\u003c/h2\u003e\u003cp\u003eComponentProps型とは、簡単に説明すると指定したコンポーネントのProps型を取得できる型です。\u003cbr\u003e\u003cbr\u003e↓こんな感じ\u003c/p\u003e\u003cpre\u003e\u003ccode\u003etype Props = ComponentProps\u0026lt;typeof Button\u0026gt;;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003e\u003cimg src=\"https://images.microcms-assets.io/assets/92d5d05a58d743f0abd69ff4e6ea61a5/2cd2e5c370cc44659337313de7847da3/%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%202022-10-19%2020.31.43.png\" alt=\"\"\u003e\u003cbr\u003e\u003cbr\u003e例えば、先ほどのボタンコンポーネントをComponentProps型に指定すると、\u003cbr\u003eボタンコンコーネントのPropsの型を全て取得できます。\u003cbr\u003e\u003cbr\u003eでは、先ほどのボタン・テキストフィールドコンポーネントを修正していきます。\u003cbr\u003e\u003cbr\u003e\u003c/p\u003e\u003ch3 id=\"h75643da8d3\"\u003eボタンコンポーネントの場合(ComponentProps ver)\u003c/h3\u003e\u003cpre\u003e\u003ccode\u003eimport type { FC, ReactNode, ComponentProps } from \"react\";\n\ntype Props = {\n  children: ReactNode;\n} \u0026amp; ComponentProps\u0026lt;\"button\"\u0026gt;;\n\nexport const Button: FC\u0026lt;Props\u0026gt; = ({ children, ...props }) =\u0026gt; {\n  return \u0026lt;button {...props}\u0026gt;{children}\u0026lt;/button\u0026gt;;\n};\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003e親コンポーネント\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eimport { Button } from \"../components/button\";\n\nconst Index = () =\u0026gt; {\n  const onClickHandler = () =\u0026gt; console.log(\"click\");\n\n  return (\n    \u0026lt;Button type=\"button\" onClick={onClickHandler}\u0026gt;\n      テスト\n    \u0026lt;/Button\u0026gt;\n  );\n};\n\nexport default Index;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003e\u003c/p\u003e\u003ch3 id=\"h2deda0682e\"\u003eテキストフィールドコンポーネントの場合(ComponentProps ver)\u003c/h3\u003e\u003cpre\u003e\u003ccode\u003eimport type { ComponentProps, FC } from \"react\";\n\ntype Props = ComponentProps\u0026lt;\"input\"\u0026gt;;\n\nexport const TextFiled: FC\u0026lt;Props\u0026gt; = ({ ...props }) =\u0026gt; {\n  return \u0026lt;input {...props} /\u0026gt;;\n};\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003e親コンコーネント\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eimport { ChangeEvent, useState } from \"react\";\nimport { TextFiled } from \"../components/textFiled\";\n\nconst Index = () =\u0026gt; {\n  const [value, setValue] = useState(\"\");\n\n  const onChangeHandler = (e: ChangeEvent\u0026lt;HTMLInputElement\u0026gt;) =\u0026gt;\n    setValue(e.target.value);\n\n  return \u0026lt;TextFiled value={value} onChange={onChangeHandler} /\u0026gt;;\n};\n\nexport default Index;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003e順番に見ていきましょう。\u003cbr\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003eボタン、テキストフィールドコンポーネント両方に\u003cstrong\u003eComponentProps\u003c/strong\u003eを追加\u003c/li\u003e\u003cli\u003e受け取るPropsをスプレット構文で一括に受け取れるように修正\u003c/li\u003e\u003cli\u003e受け取ったPropsを各要素に追加\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cbr\u003eまず1ですが、ComponentProps型を追加してボタンの要素(type,onClick,disabled等)、テキストフィールドの要素(type,onChange,value等)の型を全て受け取っています。\u003cbr\u003e\u003cbr\u003eそして2と3で受け取ったPropsを展開していている形になっています。\u003cbr\u003e\u003cbr\u003eこれで親コンポーネントからPropsを渡してもボタン、テキストフィールドコンポーネントは修正せずに済むのでメンテコストがかからずコードé‡
4ã‚‚削減できました。\u003cbr\u003e\u003cbr\u003eただし、Reactのinput要素はonChange、valueが必須なのでその場合は、下記の様にOmitでComponentPropsから必要な型は除外して、明示的にPropsの型定義を書くことでバグを回避するようにしましょう。\u003cbr\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eimport type { ChangeEventHandler, ComponentProps, FC } from \"react\";\n\ntype Props = {\n  value: string | number;\n  onChange: ChangeEventHandler;\n} \u0026amp; Omit\u0026lt;ComponentProps\u0026lt;\"input\"\u0026gt;, \"value\" |  \"onChange\" \u0026gt;;\n\nexport const TextFiled: FC\u0026lt;Props\u0026gt; = ({ value, onChange, ...props }) =\u0026gt; {\n  return \u0026lt;input {...props} value={value} onChange={onChange} /\u0026gt;;\n};\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cbr\u003e\u003c/p\u003e\u003ch2 id=\"ha214098e44\"\u003eまとめ\u003c/h2\u003e\u003cul\u003e\u003cli\u003eComponentProps型は指定したコンポーネントの型を全て取得できる\u003c/li\u003e\u003cli\u003e普通のHTMLタグの振る舞いをしてほしい場合は、ComponentPropsで型定義した方がメンテコスト、ソース量が削減できる\u003c/li\u003e\u003cli\u003eコンポーネントに必須な型はOmit等でComponentPropsから除外し、明示的にPropsの型定義をしてバグを防ぐ\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cbr\u003e\u003cbr\u003e公式ドキュメントに載っていなかったので理解するのに時間がかかりました、、\u003cbr\u003e\u003cbr\u003e間違っている部分、分かりにくい部分は\u003ca href=\"https://twitter.com/react_nextjs\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eTwitter\u003c/a\u003eでDMお願いします。\u003cbr\u003e\u003cbr\u003e\u003c/p\u003e","thumbnail":{"url":"https://images.microcms-assets.io/assets/92d5d05a58d743f0abd69ff4e6ea61a5/dc10b60546504ea99a6b5b7a3e7e3435/react.webp","height":300,"width":600},"description":"ReactのComponentProps型について解説してきます。一般的なコンポーネントの作り方から、ComponentProps型を使用したコンポーネントの作成を行い不要なPropsを取り除く事ができます。","tags":[{"id":"react","createdAt":"2022-10-20T09:16:54.710Z","updatedAt":"2022-10-20T09:16:54.710Z","publishedAt":"2022-10-20T09:16:54.710Z","revisedAt":"2022-10-20T09:16:54.710Z","tag":"React"},{"id":"typescript","createdAt":"2022-10-20T09:17:30.354Z","updatedAt":"2022-10-20T09:17:30.354Z","publishedAt":"2022-10-20T09:17:30.354Z","revisedAt":"2022-10-20T09:17:30.354Z","tag":"TypeScript"}],"category":[{"id":"frontend","createdAt":"2022-10-20T09:14:38.518Z","updatedAt":"2023-02-26T16:32:46.893Z","publishedAt":"2022-10-20T09:14:38.518Z","revisedAt":"2023-02-26T16:32:46.893Z","category":"フロントエンド","post":[{"id":"use-react-componentprops-type"},{"id":"react-state-managment"},{"id":"eslint-rule-no-nested-ternary"},{"id":"react-default-export-vs-named-export"},{"id":"equality-vs-strict-equality"}]}]}],"category":"フロントエンド","totalCount":5,"categoryType":"frontend"},"__N_SSG":true},"page":"/category/[slug]","query":{"slug":"frontend"},"buildId":"wuyDY1Tt9_JiPbBLBcH9Y","isFallback":false,"gsp":true,"scriptLoader":[]}</script>
4</body></html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.