- 投稿日:2020-03-28T20:56:15+09:00
Docker + create-react-app v3.4.1でサーバーが立ち上がらないバグ
起きたバグ
react-scripts startでサーバーを立ち上げようとしても
node_1 | yarn run v1.22.4 node_1 | $ react-scripts start node_1 | ℹ 「wds」: Project is running at http://172.26.0.2/ node_1 | ℹ 「wds」: webpack output is served from node_1 | ℹ 「wds」: Content not from webpack is served from /usr/src/app/react-sample/public node_1 | ℹ 「wds」: 404s will fallback to / node_1 | Starting the development server... node_1 | node_1 | Done in 25.46s. docker-react-app_node_1 exited with code 0というメッセージが表示されサーバーが終了する。
原因
create-react-app v3.4.1で取り込まれた下記の修正
https://github.com/facebook/create-react-app/commit/7e6d6cd05f3054723c8b015c813e13761659759e
process.stdout.isTTYかprocess.env.CIがtrueじゃないと開発用サーバーが停止するらしい。
解決方法
上のコミットのメッセージに
// Gracefully exit when stdin ends (標準入力が終了したら正常終了するよ)とあるので標準入力を終わらせないオプションをdocker-compose.ymlに追加。
具体的には下記のオプションstdin_open: trueと追加するだけ。
- 投稿日:2020-03-28T19:17:40+09:00
転職したいのでReact + Netlify + microCMSを使ってイケてるポートフォリオを作った
本記事でやること
Reactを使ったフロントエンド開発を、今時のサービスを使って簡単に効率よくできる方法を紹介します。
また、ポートフォリオの設計に関してや実装から得られたナレッジ、知っておいたほうがいい実装方法を紹介します。
私のポートフォリオはNetlifyのサーバーに上げているので、実際の挙動などは https://ykonishi.tokyo から確認できます。ちなみにポートフォリオのソースコードはGitHubにも上げているので、こちらも見ていただけたらと思います。
Yuichi KonishiポートフォリオサイトのソースコードReactとは
最近はよくSPA(Single Page Application)という言葉をよく耳にしますが、そのSPAの一つがReactです。
特徴としては、データバインディング、仮想DOM、Componentの3つがあります。
詳細については各リンクを参照してください。Netlifyとは
Netlifyは静的サイトのホスティングサービスです。
GitHubやGitLabとも簡単に連携ができるので自動デプロイやJSやAPIを必要としないフォームの作成ができるほか、Netlify Functionsで最近流行りのサーバーレス開発もできるなどフロントエンド開発には十分な機能が揃っています。
ちょっとしたサイトを公開する程度であれば無料枠で使えるので、いろいろなサイトで利用されているのをよく目にします。microCMSとは
microCMSはウォンタ株式会社が提供するヘッドレスCMSです。
ウォンタ株式会社は過去に話題になったOsushiという投げ銭サービスを運営していた会社ですね
microCMSは管理画面から入稿したデータをAPI経由で取得できるので、開発者はフロントエンドに専念することができます。
スキーマの定義はユーザーが自由に登録でき、テキストフィールドやテキストエリアはもちろん、リッチエディタや他コンテンツを参照しに行くようなフィールド定義もできます。
こちらのサービスも無料プランがあるのでちょっとしたことを始めるのには十分いいかもしれません。設計
ページ構成
ページはHome、Profile、Works、Secret Works(鍵をかけたページ)Contactの5つです。
基本的には名前のとおりのコンテンツが入っていますが、各ページの役割はこのような感じです。
HOME:ホーム
Profile:プロフィールページ
Works:実績ページ
Secret Works:パスワード必須の実績ページ
Contact:お問い合わせページコンテンツ
profileやworksなどのコンテンツはmicroCMSで管理し、API経由でデータを取得・表示させます。
デプロイ
デプロイはGitHubとNetlifyを連携することで特定のブランチがアップデートされたら実行されるようにします。
また、環境変数も同時に追加されるように設定します。フォーム
フォームはNetlify FormsというNetlifyの優れたフォーム機能があるので、こちらを使います。
Netlify FormsはSlackとの連携や登録したメールへの通知機能もあるので非常に便利です。クラス名とCSS
クラス名にはBEM記法を用いることにしました。
ReactにBEMは時代遅れな気もしますが、ページの量が少ないのと手短に実装したかったのでBEMを採用し、CSSで実装しました。ちなみにReactでCSSを使うときはカプセル化するかモジュール化するかの2通りから選ぶのがベターです。
これからのReactのスタイリングにはStyled Componentsが最高かもしれない
CSSモジュール ― 明るい未来へようこそデザイン
カラー
ベースカラーを黒にし、アクセントカラーにロイヤルブルーを入れることでクールで落ち着いた印象に仕上げました。
フォント
フォントは筑紫ゴシックをを用いることでモダンかつシャープな印象を与え、クールに加え美しさを表現しました。
巨大なタイポグラフィ
2020年は巨大なフォントのテキスト配置がトレンドになるそうなので入れてみました。
出処はこちらです
2020年に流行するWebデザインの最新トレンド14個まとめReact実装のナレッジ
React実装にはCreate React Appを使いました。
Reactを使い始めるときのデファクトスタンダードですね。環境変数
Create React Appには環境変数を提供するためのパイプラインが存在します。
使い方は、React環境が入っているディレクトリ直下に.envファイルを作成し、下記のように設定を書き込んできます。.envREACT_APP_API_KEY="xxxxxxxxxxxx"必ず
REACT_APP_
を頭に付けてください。呼び出すときは下記のようになります。
process.env.REACT_APP_API_KEYReact環境をgitで管理する際は、必ず.gitignoreに.envを追記しておくことを忘れないでください。
.envファイルには公にしたくない情報も含まれるので、ホスティングに上げないようにしておきたいからです。クリーンアップ処理
ReactでAPI処理を走らせるとき、APIが走っているのにもかかわらずページが変わってしまい下記のような警告がでる場合があります。
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.こういった警告が出るときはクリーンアップという処理が必要で、実装はこのようになります。
useEffect(() => { let cleanedUp = false; const url = new URL('https://xxxxx.com); url.pathname = '/api/v1/profile' fetch(url) .then(res => res.json()) .then(res => { if (!cleanedUp) setProfile(res) }) .catch(error => { console.log(error) }) const cleanUp = () => { cleanedUp = true; }; return cleanUp; }, []);クリーンアップはuseEffect内で使用します。
useEffectはアンマウントされるタイミングでreturn処理が走るので、return cleanUp
とすることでアンマウント時にcleanedUp
変数がtrueになりprofile
が更新されずに済みます。HTMLコードの有効化
HTMLコードをAPIで取得してそのまま表示するとき、そのままではHTMLタグごと表示されてしまうので
dangerouslySetInnerHTML
というのを使ってHTMLに変換させる必要があります。実装はこのようになります。
<div dangerouslySetInnerHTML={{ __html: profile.biography }} />名前に
dangerous
とあるように、XSS(クロスサイトスクリプティング)の引き金にもなる可能性があるので使わなくて済む場合は使わないことが推奨されています。遷移時のページ位置
ReactのようなSPAはページが一から読み込まれるのではなく、一部のDOMが更新されるだけなので遷移時にページ位置が変わることがありません。
ですので、ページが変わったら位置をTOPに戻してやる必要があります。ScrollToTop.jsxconst ScrollToTop = () => { window.scrollTo(0, 0); return null; }; export default ScrollToTop;このコンポーネントはルーティングの箇所に入れておくことで位置の切り替えができます。
Router.jsxconst Router = () => { return ( <BrowserRouter> <Route component={ScrollToTop} /> <Switch> <Route exact path="/" component={Home} /> <Route exact path="/profile" component={Profile} /> </Switch> </BrowserRouter> ); };NotFoundページ
NotFoundページの表示は、ルーティングをひと工夫することで実現させることができます。
Router.jsxconst Router = () => { return ( <BrowserRouter> <Route component={ScrollToTop} /> <Switch> <Route exact path="/" component={Home} /> <Route exact path="/profile" component={Profile} /> <Route path="*" component={NotFoundPage} /> </Switch> </BrowserRouter> ); };NotFoundPageコンポーネントはどのパスにも当てはまらなかった場合に表示するように一番下に設置し、
path="*"
とします。
また、必ず一つのコンポーネントが表示されるようにしておかないとNotFoundPageも一緒に表示されてしまうのでSwitch
で囲っておきます。ローディング
ローディングは
react-spinners
というバリエーション豊富で便利なプラグインがあるので、そちらを使いました。
導入も簡単なのでおすすめです。フォーム作成
フォームはNetlify Formsというのを使うことで簡単に実装できます。
通常のHTMLでは下記のようなコードを入れるだけでいいのですが、Reactの場合は
public/index.html
などにもう一つ別のフォームを入れる必要があります。
Netlifyボットがhtml拡張子以外のファイル内にある、フォームの設定を見に行けないためです。contact.jsx<form className="contact-form" name="contact" method="post"> <input type="hidden" name="form-name" value="contact" /> <label> お名前<span className="required-attention">(必須)</span> <input className="contact-form__input" type="text" name="username" required/> </label> <label> Email<span className="required-attention">(必須)</span> <input className="contact-form__input" type="email" name="email" required/> </label> <label> 会社名 <input className="contact-form__input" type="text" name="company"/> </label> <label> 本文<span className="required-attention">(必須)</span> <textarea className="contact-form__textarea field__textarea" name="message" required></textarea> </label> <button className="contact-form__submit" type="submit">送信</button> </form>追加する別のフォームは下記のようになります。
contact.jsxで入れたフィールドはこちらにも必ず追加してください。属性はtypeとnameだけで十分です。public/index.html<!-- A little help for the Netlify bots if you're not using a SSG --> <form name="contact" netlify netlify-honeypot="bot-field" hidden> <input type="text" name="name" /> <input type="email" name="email" /> <input type="text" name="company" /> <textarea name="message"></textarea> </form>詳しくはこちらを見ていただければと思います。
https://www.netlify.com/blog/2017/07/20/how-to-integrate-netlifys-form-handling-in-a-react-app/メニュー
メニューはreact-springを使って実装しました。
独自仕様が多いので使いこなすのには少し時間がかかります。
react-springはReactでアニメーションを表現するためのプラグインで、Hooks用のプラグインでスポンサーやコントリビューターも充実しているのでHooks時代のデファクトスタンダードになるかもしれません。(もうすでにそうなっているかも )参考
React Spring最後に
React + Netlify + microCMSを試しに使ってポートフォリオを作ってみた結果、データ管理やサーバーのことをほとんど考えずにフロントエンドに専念できました。
microCMSについては今回初めて使ってみましたが、スキーマを自分で定義してカスタマイズできるほか、RDBのようにほかのコンテンツ(テーブルのようなもの)を参照しに行く定義もできるので非常に使い勝手が良かったです。
メンバーの権限管理機能やほかサービスとのデータ連携機能もあるので、仕事で使うのにもいいかもしれません。Web制作で頭を悩ましがちなお問い合わせページでは、Netlifyにある便利なフォーム機能があったおかげで一瞬で片付きました。
Webhooks連携や登録したメールアドレスへの通知機能があるのは嬉しいポイントです。デザイン周りではなるべくシンプルにし、行間、テキストの両端揃え、フォントにも気を配りました。
また、質素な見た目にちょっとした動きを与えているので、飽きさせない工夫も取り入れました。フロント面でもバックエンド面でもなかなかイケてるポートフォリオサイトが出来上がったのではないでしょうか。
私自身フロントエンド開発に疎いので、ご意見やアドバイスなどあれば大歓迎です!
参考
- 投稿日:2020-03-28T19:17:40+09:00
転職活動始めるのでReact + Netlify + microCMSを使ってイケてるポートフォリオを作った
本記事でやること
Reactを使ったフロントエンド開発を、今時のサービスを使って簡単に効率よくできる方法を紹介します。
また、ポートフォリオの設計に関してや実装から得られたナレッジ、知っておいたほうがいい実装方法を紹介します。
私のポートフォリオはNetlifyのサーバーに上げているので、実際の挙動などは https://ykonishi.tokyo から確認できます。ちなみにポートフォリオのソースコードはGitHubにも上げているので、こちらも見ていただけたらと思います。
Yuichi KonishiポートフォリオサイトのソースコードReactとは
最近はよくSPA(Single Page Application)という言葉をよく耳にしますが、そのSPAの一つがReactです。
特徴としては、データバインディング、仮想DOM、Componentの3つがあります。
詳細については各リンクを参照してください。Netlifyとは
Netlifyは静的サイトのホスティングサービスです。
GitHubやGitLabとも簡単に連携ができるので自動デプロイやJSやAPIを必要としないフォームの作成ができるほか、Netlify Functionsで最近流行りのサーバーレス開発もできるなどフロントエンド開発には十分な機能が揃っています。
ちょっとしたサイトを公開する程度であれば無料枠で使えるので、いろいろなサイトで利用されているのをよく目にします。microCMSとは
microCMSはウォンタ株式会社が提供するヘッドレスCMSです。
ウォンタ株式会社は過去に話題になったOsushiという投げ銭サービスを運営していた会社ですね
microCMSは管理画面から入稿したデータをAPI経由で取得できるので、開発者はフロントエンドに専念することができます。
スキーマの定義はユーザーが自由に登録でき、テキストフィールドやテキストエリアはもちろん、リッチエディタや他コンテンツを参照しに行くようなフィールド定義もできます。
こちらのサービスも無料プランがあるのでちょっとしたことを始めるのには十分いいかもしれません。設計
ページ構成
ページはHome、Profile、Works、Secret Works(鍵をかけたページ)Contactの5つです。
基本的には名前のとおりのコンテンツが入っていますが、各ページの役割はこのような感じです。
HOME:ホーム
Profile:プロフィールページ
Works:実績ページ
Secret Works:パスワード必須の実績ページ
Contact:お問い合わせページコンテンツ
profileやworksなどのコンテンツはmicroCMSで管理し、API経由でデータを取得・表示させます。
デプロイ
デプロイはGitHubとNetlifyを連携することで特定のブランチがアップデートされたら実行されるようにします。
また、環境変数も同時に追加されるように設定します。フォーム
フォームはNetlify FormsというNetlifyの優れたフォーム機能があるので、こちらを使います。
Netlify FormsはSlackとの連携や登録したメールへの通知機能もあるので非常に便利です。クラス名とCSS
クラス名にはBEM記法を用いることにしました。
ReactにBEMは時代遅れな気もしますが、ページの量が少ないのと手短に実装したかったのでBEMを採用し、CSSで実装しました。ちなみにReactでCSSを使うときはカプセル化するかモジュール化するかの2通りから選ぶのがベターです。
これからのReactのスタイリングにはStyled Componentsが最高かもしれない
CSSモジュール ― 明るい未来へようこそデザイン
カラー
ベースカラーを黒にし、アクセントカラーにロイヤルブルーを入れることでクールで落ち着いた印象に仕上げました。
フォント
フォントは筑紫ゴシックをを用いることでモダンかつシャープな印象を与え、クールに加え美しさを表現しました。
巨大なタイポグラフィ
2020年は巨大なフォントのテキスト配置がトレンドになるそうなので入れてみました。
出処はこちらです
2020年に流行するWebデザインの最新トレンド14個まとめReact実装のナレッジ
React実装にはCreate React Appを使いました。
Reactを使い始めるときのデファクトスタンダードですね。環境変数
Create React Appには環境変数を提供するためのパイプラインが存在します。
使い方は、React環境が入っているディレクトリ直下に.envファイルを作成し、下記のように設定を書き込んできます。.envREACT_APP_API_KEY="xxxxxxxxxxxx"必ず
REACT_APP_
を頭に付けてください。呼び出すときは下記のようになります。
process.env.REACT_APP_API_KEYReact環境をgitで管理する際は、必ず.gitignoreに.envを追記しておくことを忘れないでください。
.envファイルには公にしたくない情報も含まれるので、ホスティングに上げないようにしておきたいからです。クリーンアップ処理
ReactでAPI処理を走らせるとき、APIが走っているのにもかかわらずページが変わってしまい下記のような警告がでる場合があります。
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.こういった警告が出るときはクリーンアップという処理が必要で、実装はこのようになります。
useEffect(() => { let cleanedUp = false; const url = new URL('https://xxxxx.com); url.pathname = '/api/v1/profile' fetch(url) .then(res => res.json()) .then(res => { if (!cleanedUp) setProfile(res) }) .catch(error => { console.log(error) }) const cleanUp = () => { cleanedUp = true; }; return cleanUp; }, []);クリーンアップはuseEffect内で使用します。
useEffectはアンマウントされるタイミングでreturn処理が走るので、return cleanUp
とすることでアンマウント時にcleanedUp
変数がtrueになりprofile
が更新されずに済みます。HTMLコードの有効化
HTMLコードをAPIで取得してそのまま表示するとき、そのままではHTMLタグごと表示されてしまうので
dangerouslySetInnerHTML
というのを使ってHTMLに変換させる必要があります。実装はこのようになります。
<div dangerouslySetInnerHTML={{ __html: profile.biography }} />名前に
dangerous
とあるように、XSS(クロスサイトスクリプティング)の引き金にもなる可能性があるので使わなくて済む場合は使わないことが推奨されています。遷移時のページ位置
ReactのようなSPAはページが一から読み込まれるのではなく、一部のDOMが更新されるだけなので遷移時にページ位置が変わることがありません。
ですので、ページが変わったら位置をTOPに戻してやる必要があります。ScrollToTop.jsxconst ScrollToTop = () => { window.scrollTo(0, 0); return null; }; export default ScrollToTop;このコンポーネントはルーティングの箇所に入れておくことで位置の切り替えができます。
Router.jsxconst Router = () => { return ( <BrowserRouter> <Route component={ScrollToTop} /> <Switch> <Route exact path="/" component={Home} /> <Route exact path="/profile" component={Profile} /> </Switch> </BrowserRouter> ); };NotFoundページ
NotFoundページの表示は、ルーティングをひと工夫することで実現させることができます。
Router.jsxconst Router = () => { return ( <BrowserRouter> <Route component={ScrollToTop} /> <Switch> <Route exact path="/" component={Home} /> <Route exact path="/profile" component={Profile} /> <Route path="*" component={NotFoundPage} /> </Switch> </BrowserRouter> ); };NotFoundPageコンポーネントはどのパスにも当てはまらなかった場合に表示するように一番下に設置し、
path="*"
とします。
また、必ず一つのコンポーネントが表示されるようにしておかないとNotFoundPageも一緒に表示されてしまうのでSwitch
で囲っておきます。ローディング
ローディングは
react-spinners
というバリエーション豊富で便利なプラグインがあるので、そちらを使いました。
導入も簡単なのでおすすめです。フォーム作成
フォームはNetlify Formsというのを使うことで簡単に実装できます。
通常のHTMLでは下記のようなコードを入れるだけでいいのですが、Reactの場合は
public/index.html
などにもう一つ別のフォームを入れる必要があります。
Netlifyボットがhtml拡張子以外のファイル内にある、フォームの設定を見に行けないためです。contact.jsx<form className="contact-form" name="contact" method="post"> <input type="hidden" name="form-name" value="contact" /> <label> お名前<span className="required-attention">(必須)</span> <input className="contact-form__input" type="text" name="username" required/> </label> <label> Email<span className="required-attention">(必須)</span> <input className="contact-form__input" type="email" name="email" required/> </label> <label> 会社名 <input className="contact-form__input" type="text" name="company"/> </label> <label> 本文<span className="required-attention">(必須)</span> <textarea className="contact-form__textarea field__textarea" name="message" required></textarea> </label> <button className="contact-form__submit" type="submit">送信</button> </form>追加する別のフォームは下記のようになります。
contact.jsxで入れたフィールドはこちらにも必ず追加してください。属性はtypeとnameだけで十分です。public/index.html<!-- A little help for the Netlify bots if you're not using a SSG --> <form name="contact" netlify netlify-honeypot="bot-field" hidden> <input type="text" name="name" /> <input type="email" name="email" /> <input type="text" name="company" /> <textarea name="message"></textarea> </form>詳しくはこちらを見ていただければと思います。
https://www.netlify.com/blog/2017/07/20/how-to-integrate-netlifys-form-handling-in-a-react-app/メニュー
メニューはreact-springを使って実装しました。
独自仕様が多いので使いこなすのには少し時間がかかります。
react-springはReactでアニメーションを表現するためのプラグインで、Hooks用のプラグインでスポンサーやコントリビューターも充実しているのでHooks時代のデファクトスタンダードになるかもしれません。(もうすでにそうなっているかも )参考
React Spring最後に
React + Netlify + microCMSを試しに使ってポートフォリオを作ってみた結果、データ管理やサーバーのことをほとんど考えずにフロントエンドに専念できました。
microCMSについては今回初めて使ってみましたが、スキーマを自分で定義してカスタマイズできるほか、RDBのようにほかのコンテンツ(テーブルのようなもの)を参照しに行く定義もできるので非常に使い勝手が良かったです。
メンバーの権限管理機能やほかサービスとのデータ連携機能もあるので、仕事で使うのにもいいかもしれません。Web制作で頭を悩ましがちなお問い合わせページでは、Netlifyにある便利なフォーム機能があったおかげで一瞬で片付きました。
Webhooks連携や登録したメールアドレスへの通知機能があるのは嬉しいポイントです。デザイン周りではなるべくシンプルにし、行間、テキストの両端揃え、フォントにも気を配りました。
また、質素な見た目にちょっとした動きを与えているので、飽きさせない工夫も取り入れました。フロント面でもバックエンド面でもなかなかイケてるポートフォリオサイトが出来上がったのではないでしょうか。
私自身フロントエンド開発に疎いので、ご意見やアドバイスなどあれば大歓迎です!
参考
- 投稿日:2020-03-28T19:10:04+09:00
React入門 ~PropTypes編~
React入門記事、第3弾。
今回はコンポーネントに渡すpropsの使用を補助するものであるPropTypes
について書きました。PropTypesとは?
Reactで使用するコンポーネントにはpropsを渡して、レンダリング内容に変化をつけたりできます。
Reactで開発する上ではほぼ必須のものであるものの、通常ではどんな値でも受け取ることができてしまいます(TypeScriptであればまた事情が変わってきますが)
そのため、想定と違う値が渡されると予期しない動作をする可能性があります。それを防ぐため、渡された値の型チェックを行うのが
PropTypes
です。
元々はReact本体に組み込まれていましたが、バージョン15.5よりprop-types
という別パッケージとして切り分けされました。インストール
$ yarn add prop-types今回の使用バージョンは
15.7.2
です。使い方
React公式ドキュメントはこちら。
React - Doc - PropTypes を用いた型チェック基本的な使い方
まずは簡単な使い方から。
App.jsimport React from 'react'; import PropsTypesComponent from './PropTypesComponent'; const App = () => { return ( <PropsTypesComponent name="太郎" /> ) } export default App;PropsTypesComponent.jsimport React from 'react'; import PropTypes from 'prop-types'; const PropTypesComponent = props => { return ( <h2>Hello {props.name}</h2> ); } PropTypesComponent.propTypes = { name: PropTypes.string }; export default PropTypesComponent;ライブラリをimport
import PropTypes from 'prop-types';propsごとのバリデーションを記述
コンポーネント.propTypes = { props名: PropTypes.バリデーションの種類 }↓
今回の場合PropTypesComponent.propTypes = { name: PropTypes.string };これだけでバリデーションチェックが行われ、無効な値が渡された場合はDevToolsのコンソールにWarningが出力されます。
上記の例では問題ありませんが、例えばPropsTypesComponentに渡しているnameの値を1など、string以外の値にしてみます。
すると、以下のようなWarningがコンソールに出力されているはずです。※1つ注意点として、このバリデーションチェックはパフォーマンス上の理由から開発モードの場合のみ動作します。
バリデーションの種類
数値
PropTypes.number受け付ける例
1 1.0文字列
PropTypes.string受け付ける例
"太郎" "1"真偽値
PropTypes.bool受け付ける例
true false一応補足として、あくまで真偽値なので
"true"
などはダメです。文字列扱いなので、バリデーションに引っ掛かります。配列
PropTypes.array受け付ける例
[1, 'A'] [{ id: 'A'}, { id: 'B' }]配列であれば、その中の値の型までは問わないため非推奨のようです。
中の値の型までチェックする場合はarrayOf
を使います。PropTypes.arrayOf(バリデーションの種類) // 例 PropTypes.arrayOf(PropTypes.number)受け付ける例
※PropTypes.arrayOf(PropTypes.number)の場合[1, 2, 3]オブジェクト
PropTypes.object受け付ける例
{ a: 'A', b: 'B' } などオブジェクトであれば、その中の値の型までは問わないため非推奨のようです。
中の値の型までチェックする場合はobjectOf
かshape
、もしくはexact
を使います。
objectOf
は特定の型のみの場合。PropTypes.objectOf(バリデーションの種類) // 例 PropTypes.objectOf(PropTypes.number)受け付ける例
※PropTypes.objectOf(PropTypes.number)の場合{ a: 1, b: 2 }
shape
は型がバラバラの場合。PropTypes.shape({ props名: バリデーションの種類, props名: バリデーションの種類 }) // 例 PropTypes.shape({ num: PropTypes.number, str: PropTypes.string })受け付ける例
※上の設定例の場合{ num: 1, str: '太郎' }
exact
も型がバラバラの場合です。
shape
との違いは、バリデーション定義した以外のものがオブジェクトに追加されているとバリデーションに引っ掛かります。こちらの方がより厳密にpropsをチェックする感じです。PropTypes.exact({ props名: バリデーションの種類, props名: バリデーションの種類 }) // 例 PropTypes.exact({ num: PropTypes.number, str: PropTypes.string })受け付ける例
※上の設定例の場合{ num: 1, str: '太郎' } // ここにこの二つ以外のキー、値があると警告関数
PropTypes.func受け付ける例
() => { console.log('func'); }シンボル
PropTypes.symbol受け付ける例
Symbol() Symbol('test')恥ずかしながら自分はシンボルって何?状態だったので調べたのですが、ES6で追加された新しいプリミティブのデータ型だったのですね。
でも、いまいち使い方がよくわからない...。
特定の値のいずれかの場合
PropTypes.oneOf(['値1', '値2']) // 例 PropTypes.oneOf(['A', 'B', 'C'])受け付ける例
※上の設定例の場合'A' 'B' 'C'いろんなデータ型が渡される可能性がある場合
PropTypes.oneOfType([ バリデーションの種類, バリデーションの種類 ]) // 例 PropTypes.oneOfType([ PropTypes.number, PropTypes.string ])受け付ける例
※上の設定例の場合1 '1' 'A'クラスオブジェクト
PropTypes.instanceOf(クラス名) // 例 PropTypes.instanceOf(Date)受け付ける例
※上の設定例の場合new Date()React Element
PropTypes.element受け付ける例
<Test /> // 独自定義のコンポーネント <p>Test</p>ちなみに
elementType
というものもあるのですが、element
との違いや、どういう値を想定したものなのかがよくわかりませんでした...。レンダリングできるもの
PropTypes.node受け付ける例
1 'A' ['a', 'b'] <p>Test</p> <Test /> // 独自定義のコンポーネント数値、文字列、配列、React Elementであればいいようです。
真偽値やオブジェクトはバリデーションに引っ掛かりました。必須
PropTypes.バリデーションの種類.isRequired // 例 PropTypes.number.isRequired PropTypes.any.isRequired // 型は任意カスタムルール
// カスタムルールの定義 const customProp = (props, propName, componentName) => { if (!/test/.test(props[propName])) { return new Error( 'Invalid prop `' + propName + '` supplied to' + ' `' + componentName + '`. Validation failed.' ); } } // カスタムルールの使用 コンポーネント名.propTypes = { props名: customProp }この例はpropsの値に
test
という文字列が含まれているかチェックするものです(公式ドキュメントのコードをベースにしています)propsのデフォルト値
defaultProps
を使って、propsのデフォルト値を設定できます。
もしそのpropsに値が渡されなかった場合は、このデフォルト値がセットされます。
また、バリデーションチェックと並行して使用している場合は、このデフォルト値セットが行われた後でバリデーションチェックが行われます。コンポーネント名.defaultProps = { props名: 値 } // 例 PropTypesComponent.defaultProps = { defaultValue: 'default' }
ずらっとルールを書いていきましたが、実は自分はこの
PropTypes
をあまり活用できていなかったりします(苦笑)
なので、今回記事を書きながら、あーこういうことできるものだったんだなと改めて思いました。渡すpropsが多いコンポーネントだとルールを定義するのが大変ではありますが、そのルールを見ればどんな値が渡されてくるのか、またそのコンポーネントを使用するにはどんな値が必要なのか一目瞭然でわかるので、今後活用していきたいですね。
参考リンク
- 投稿日:2020-03-28T18:09:48+09:00
問答無用でReactコンポーネントを初期化・リセットする方法
はじめに
とにかくコンポーネントをリセットしたい!マウントからやり直したい!
という時に使えるテクニックを紹介します。やり方
初期化したいコンポーネントの
props
にkey
を設定し、keyを更新します。const Component = () => { return ( <div key={something}> ... </div> ) }説明
コンポーネントにはライフサイクルがあります。
Reactコンポーネントはとても賢いので、うまく差分を計算してコンポーネントは不要な再描画が走らないようにしています。
そのため、マウント後の更新に関しては基本的にUpdateが適用されます。
一方で
key
はコンポーネントの一意性を保つための仕組みですので、key
が更新されるという事は、まるっきり新しいコンポーネント扱いになります。そのため、Updateではなく、Mountから新規で描画できる、というわけです。
- 投稿日:2020-03-28T17:45:45+09:00
ubuntu系LinuxでReact環境を1分で作る
必要なモジュールインストール
$ sudo apt install -y nodejs $ sudo apt install -y npm $ sudo npm install n -g $ sudo n stable $ sudo npm install -g yarn $ yarn global add create-react-appバージョン確認
$ cat /etc/lsb-release DISTRIB_ID=LinuxMint DISTRIB_RELEASE=19.3 DISTRIB_CODENAME=tricia DISTRIB_DESCRIPTION="Linux Mint 19.3 Tricia" $ node -v v12.16.1 $ npm -v 6.13.4 $ yarn -v 1.22.4~/.bashrcにパスを追加
export PATH="$PATH:yarn global bin
"$ create-react-app sample $ cd sample $ yarn starthttp://localhost:3000/
にアクセスしてreactロゴがクルクルしていればok, react!
- 投稿日:2020-03-28T17:34:10+09:00
フロントエンド開発超初学者が贈る、0から始めるReactハンズオン
始めに
レガシー言語しか触ったことのなかった私が2019年12月中旬に初めて世間で一般的に使用されているプログラミング言語に触れて衝撃と感動を覚えてから早3カ月、、、(その時の記事)
あれからも昼休みや休日を利用して様々なイベントへの参加や自己啓発を行い、知識レベルが浦島太郎状態な現状を脱却すべく研鑽を積んできました。
Lambda関数を使用したサーバーレスなシステム作りに携わったり、Spring bootを使った開発技術を学んだり、HTML5プロフェッショナル認定試験の勉強をやったり...(インプットに夢中になってアウトプットさぼってましたすみません)
その一環でReactを使ったハンズオン学習をする機会があり、その時学んだ内容を自分の中に定着させる意味も込めて記事にしようと思ったので、お時間がある方はお付き合いください。タイトルにもありますが、自分は超初学者ですので、その認識間違ってるよ!ってところなどありましたら優しくコメントくださると嬉しいです!
そもそもReactってなんぞ
Reactとは、webアプリ開発で使用されるJavaScriptのライブラリです。
webアプリのアーキテクチャの話でよく出てくるMVCモデルのView部分の実装に使われることが多いみたいです。本記事ではこのReactを使って、
① Hello Worldの表示
② ①+αの表示
を作っていきます。ハンズオンを実施する前に...
本当にCOBOLのようなレガシー言語しか知らなかった私のこの3カ月の経験からですが、私のような本当にまっさらな知識状態でweb開発の勉強がしたい!と思っている方はReactに触れる前にHTML,CSS,JavaScriptの学習をちょろっとでもいいので実施するのをオススメします。
私も昨年の12月Dev fest Tokyoというイベントに行った際angularというJavaScriptのフレームワークでハンズオン体験をする機会があったのですが、よーわからんけどコピペしてたらなんかいい感じのショッピングサイトが出来上がったという感じでした。というのも、やはりReactの学習と言ってもその中にはHTMLやJavaScriptの概念がふんだんに出てきて、それらは知っている前提で進んでいくのでそもそもの基礎知識がないとただソースをコピペして成果物を作るだけになってしまいます。
とはいっても、コピペだろうと普段自分が使っているwebサービスに似たものが自分の手によって形となって出来上がるのは、それはそれで感動するのでお試しで実施するのはいいかもしれません。
(かくいう私もこのangularのチュートリアルでwebアプリ開発の楽しさに目覚めて今もこうしてモチベーション高く学習しております。)それでは早速始めていきたいと思います!!
1-1)Reactを使う環境を設定する
Reactの環境導入は自PCにNode.jsというJavaScriptを使う環境をインストールするだけです。
私はMacbookを使用しているので、こちらの方の記事を参考に導入しました。
基本的にはこの通りに実施すれば問題なくReactの環境を導入できるはずです。
この時npmというパッケージ管理ツールが一緒にインストールされるのですが、これを使ってプロジェクト生成をしたりアプリを起動させたりします。1-2)成果物のひな形を作る
今回は私のような初心者でもReactを使ったアプリ開発を体系的に理解しやすいように、公式が提供している"create-react-app"というジェネレータを使ってアプリ全体の枠を最初に作ります。
家だけ先に作って、中に入れる家具や家電は後から追加していくイメージですね。// ひな形の生成 npx create-react-app react-handson // 生成したプロジェクトへ移動 cd react-handsonここでひな形生成時にしれっとnpmではなくnpxを使っていますが、npxはnpmパッケージを簡単に実行できるコマンドで、これもnpmをインストールすれば勝手に使えるようになっています。
ここではグローバルインストールせずに1度だけ実行するために使っています。
要は自分のPCにインストールしなくても一瞬だけ借りて使い終わったら速攻で消してくれる便利なコマンドです。ここで一度以下コマンドでアプリを起動してみましょう。
npm start
するとしばらくしてブラウザが勝手に開くので、以下のような画面がでればOKです。
2-1)Hello Worldを表示させる
今回は理解しやすくするためにジェネレータによって生成されたコードのうち使わないものは削除します。
rm public/manifest.json rm src/*その後、以下のような最小構成のファイルを作成します。
src/index.jsimport React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; ReactDOM.render(<App />, document.getElementById('root'));src/App.jsimport React from 'react'; function App() { return <h1>Hello World</h1>; } export default App;htmlファイル内の不要な記述も削除して、以下のようにします。
public/index.html<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> <title>React App</title> </head> <body> <div id="root"></div> </body> </html>この状態で
npm start
すると以下のようにHello Worldが出ると思います。2-2)構成と解説
ここまでの時点でディレクトリ構成は以下のようになっているかと思います。
. ├── node_modules // 外部ライブラリ ├── README.md // プロジェクトの説明などを記載するファイル ├── package.json // 依存するライブラリなどを記載するファイル ├── public // Web上に公開するディレクトリ │ ├── favicon.ico // ブラウザのタブに出るアイコン │ └── index.html // エントリーポイントとなるhtml └── src // 開発者が書くコードを置くディレクトリ ├── App.js // ルートコンポーネント └── index.js // ReactのコードのエントリーポイントここでHello Worldの描画に直接関わっている人たちは以下の3人
・index.html
・App.js
・index.jsまず
index.html
ですが、ここに記載する内容が実際に画面に表示されます。
今回のソースで言うと、画面に表示される所はここ↓index.html<body> <div id="root"></div> </body>これだけだと、画面には"root"というid属性を持った空のdivタグが表示されるだけです。
ではなぜ画面にHello Worldが表示されたかというと、誰かが"root"というid属性をキーにdivタグの中にHello Worldを入れたのです。
そのHello Worldという中身を持っているのがApp.js
です。src/App.jsimport React from 'react'; function App() { return <h1>Hello World</h1>; } export default App;
App.js
の中には<h1>Hello World</h1>
というhtmlタグを戻す関数があり、この戻り値がdivタグに入っている形になります。
そして、このhtmlタグをdivタグの中にぶち込んでくれるのがindex.js
です。
index.js
の中身の内、上3行はただのimportなので実質の中身はこの1行。src/index.jsReactDOM.render(<App />, document.getElementById('root'));ぱっと見よくわからないことをやっているように見えますがこれを日本語にすると、App関数の戻り値をindex.html内にあるid属性が"root"のタグの中にレンダリングするということです。
このレンダリングというのがreactの特徴の一つであり、reactの開発はこのように別々で作ったパーツ(コンポーネント)をレンダリング処理によって別のコンポーネントと組み合わせ、出来上がったものを画面に表示するという流れになります。
機能を追加して行く場合、このコンポーネントやコンポーネントを統合するコードを増やしていく事になります。3-1)コンポーネントを増やしてみる
コンポーネントの使い方を理解するために、複数のコンポーネントを作成しそれらを組み合わせてみましょう。
新しくsrcディレクトリ配下にcomponentsディレクトリを作成し、そこに以下のような
Hello.js
を作成します。src/components/Hello.jsimport React from 'react'; function Hello() { return ( <div> <h1>Hello World</h1> <p>konnitiwa sekai</p> </div> ); } export default Hello;作成したHelloコンポーネントを画面に表示させるために
App.js
を修正します。src/App.jsimport React from 'react'; import Hello from './components/Hello'; // Helloコンポーネントをimportする function App() { return <Hello />; // importしたHelloコンポーネントを返すように変更する } export default App;importしたコンポーネントはhtmlタグのようにして使うことができます。
次に、引数を渡してそれをコンポーネントに埋め込んだ関数も追加してみます。
作成したcomponentsディレクトリに以下のような
Greet.js
を作成します。src/components/Greet.jsimport React from 'react'; function Greet({ name }) { return <p>Hello {name}さん!</p>; // {}で囲うと変数を埋め込むことができる } export default Greet;最後にGreetコンポーネントを呼び出すロジックを
App.js
に追加します。src/App.jsimport React from 'react'; import Hello from './components/Hello'; import Greet from './components/Greet'; // importを追加 function App() { return ( <div> <Hello /> {/* 引数は属性として渡す */} <Greet name="Qiita" /> </div> ); } export default App;引数の受け渡し方法ですが、属性に値を設定することで渡すことができます。
この時、引数を渡す時の属性名と受け取る時の変数名は同一でないといけないのでご注意ください。
・function Greet({ name }) {
・<Greet name="Qiita" />
上記の修正が反映した状態でアプリを起動させて、以下が表示されたら成功です。
最後に
webアプリ開発の'ウェ'の字も知らなかった3ヶ月半前からどっぷりと開発知識の習得に邁進していますが、レガシー業界の住人である私にとってこの業界の技術を学ぶのは本当に刺激的です。
今後も記事にしてアウトプットすることでどんどん知識を自分に落とし込んでいこうと思います。
ちなみに、本当はuseStateを用いた状態管理やらページ遷移やらReduxを用いた状態管理やらも書きたかったのですが、量がすごい事になるのでまた別で書こうと思います。ここまで読んでくださりありがとうございました!
- 投稿日:2020-03-28T10:38:05+09:00
日々のうんちをシェアするアプリを作る~その1~
うんちしぇあ。作ります
技術の勉強をかねて、何か作りたいなあ、、、なんか良いアイディアないかなあ、、、
そんな思いを日々持っていました。
しかし特に決まらず、ふと彼女に「なんかほしいアプリない?」って聞いてみました。
すると
「毎日何回うんちしたかシェアするアプリかなあ、、、、」は!?
こいつ天才か!?僕はそう思いました。
だから作ります。うんちしぇあ。使う技術
僕はReactというものが書けます。少しですが。
だからNext.jsやってみたいなーっていう安直な理由でNext.js書きます。
あとRailsもかけるからAPI的に使います。とまあ、明らかに技術力は低いので、間違っているところ・アドバイス・情報共有などあればバンバンください。絶対に受け入れます。一緒に成長していきましょう。
女性ならプライベートでの勉強会も早速作って行くよん
まずはサクッとNext.jsのチュートリアルを終わらせました。。。しかし!!良さが全然わからん。なんか英語だし。
はい。もう良いです。作りながら勉強します。
やっぱうんちしぇあ。だしうんちのコンポーネントからだよね。
pages/unchis/index.ts// packages import moment from "moment"; // types import {IUnchi} from "../../types/unchi"; //components import { Calendar } from "../components/Calendar"; import {useState} from "react"; import UnchiLists from "../components/UnchiLists"; const today: string = moment().format("YYYY-MM-DD").toString(); const Index = () => { const searchUnchi = (date: string): IUnchi => { const emptyUnchi: IUnchi = { date: date, count: 0 } return emptyUnchi; }; const [unchi, setUnchi] = useState<IUnchi>(searchUnchi(today)); const handleClick = (date: string) => { setUnchi(searchUnchi(date)) }; return ( <> <h1>今日のうんち</h1> <Calendar onClick={handleClick} /> <UnchiLists {...unchi} /> <style> {` html { width: 100%; height: 100%; } body { width: 100%; height: 100%; position: relative; } `} </style> </> ) } export default Indexpages/components/UnchiLists.tsximport {IUnchi} from "../../types/unchi"; import moment from "moment"; import { Card } from "./Cards" const UnchiLists = (unchi: IUnchi) => { return ( <Card> {moment(unchi.date).format('M月D日')}のうんち <ul> <li> {unchi.count}回 </li> </ul> </Card> ) } export default UnchiListsCalendarはネットにあるコピペで使えるデザイン付きのやつを利用させてもらいました。
いきなりちょっと本気出しちゃったかな・・・
これで一旦日付に対してうんちの回数を確認できるようになったから次はうんちの登録画面かな。今回は特に難しいことや困ったことがなかったので技術についてあまり触れてませんが、詰まったところなどあれば適宜共有していこうかと思っています。
その2もお楽しみに!!
- 投稿日:2020-03-28T01:29:06+09:00
【React】export default しか無いコンポーネントの記述の仕方
- 投稿日:2020-03-28T01:08:46+09:00
【React】AplloClientを使ってGraphQLサーバにアクセスする
概要
- ReactからGraphQLサーバにアクセスするためのClientライブラリとしてApolloClientがあります
- 数年前にさわったことがありましたがHooks対応してかなり使いやすくなっていたのでセットアップとQuery/Mutationの叩き方を簡単に紹介します
- ※ApolloClientは執筆日時点(2020/3/28)でbeta版であるv3系を使っています
事前準備
- Reactの追加
yarn add react react-dom
- index.htmlの作成
index.html<div id="root"></div> <script src="index.js"></script>
- index.jsの作成
index.jsimport React from 'react'; import { render } from 'react-dom'; import App from './src/App'; render(<App />, document.getElementById('root'));
- src/App.jsの作成
src/App.jsimport React from 'react'; function App() { return ( <div> <h1>Hello</h1> </div> ); } export default App;
- 起動
- 今回は手っ取り早く試すためParcelを使います
npx parcel-bundler index.html
- http://localhost:1234 で起動します
ApolloClientのセットアップ
- ここからが本題です
- まずはライブラリを追加します
yarn add @apollo/client graphql
- 次にGraphQLサーバのアクセス先などを設定します
- ApolloClientの公式ページに登場するTODOアプリのGraphQLサーバを使っています
- ブラウザで https://plp0mopxq.sse.codesandbox.io/ にアクセスするとPlaygroundでスキーマなどを確認できます
src/graphql/client.jsimport { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client'; export default new ApolloClient({ cache: new InMemoryCache(), link: new HttpLink({ uri: 'https://plp0mopxq.sse.codesandbox.io/graphql', }), });
- App.jsに反映します
src/App.jsimport React from 'react'; import { ApolloProvider } from '@apollo/client'; import client from './graphql/client'; function App() { return ( <ApolloProvider client={client}> <h1>Hello</h1> </ApolloProvider> ); } export default App;
- これでセットアップ完了です
Queryを実行する
- 実行するQueryを定義するファイルを作成します
- Todoの全量を取得する
GET_TODOS
と、指定したIDのTodoを1件取得するGET_TODO
の2つを定義します- Query実行時に引数を渡す場合は
GET_TODO
で定義しているような書き方をしますsrc/graphql/query.jsimport { gql } from '@apollo/client'; // 全件取得 export const GET_TODOS = gql` query getTodos { todos { id type } } `; // 指定したIDのTODOを1件取得 export const GET_TODO = gql` query getTodo($id: String!) { todo(id: $id) { id type } } `;useQuery
- コンポーネントから
GET_TODOS
のQueryを呼び出しますuseQuery
を使うとコンポーネントが生成された時にQueryが実行されます
- 今回のように一覧を取得して表示するようなケースで使うイメージですね
- 今回実行する
GET_TODOS
は引数なしですが、ありの場合はuseQuery
の第2引数で指定することができます
useQuery(GET_TODOS, { variables: { xx: 'xx' } })
src/components/TodoList.jsimport React from 'react'; import { useQuery } from '@apollo/client'; import { GET_TODOS } from '../graphql/query'; function TodoList() { // Queryを実行 const { loading, error, data } = useQuery(GET_TODOS); if (loading) return <p>...loading</p>; if (error) return <p>{error.message}</p>; return ( <div> <h2>TodoList</h2> {data.todos.map(todo => ( <p key={todo.id}>{todo.id}: {todo.type}</p> ))} </div> ); } export default TodoList;
- App.jsに反映します
src/App.jsimport React from 'react'; import { ApolloProvider } from '@apollo/client'; import client from './graphql/client'; // importを追加 import TodoList from './components/TodoList'; function App() { return ( <ApolloProvider client={client}> <h1>Hello</h1> {/* コンポーネントを追加 */} <TodoList /> </ApolloProvider> ); } export default App;useLazyQuery
- IDを指定してTodoを1件取得する
GET_TODO
をコンポーネントから呼び出します- ユーザのアクションなどをきっかけにQueryを実行したい時は
useLazyQuery
を使います- Query実行時の引数は
{ variables: {...} }
といった形式でvariables
は固定文言でその中に必要な値をセットしますsrc/components/Todo.jsimport React, { useRef } from 'react'; import { useLazyQuery } from '@apollo/client'; import { GET_TODO } from '../graphql/query'; function Todo() { const inputRef = useRef(null); // getTodoを呼び出すとQueryが実行される const [getTodo, { loading, error, data }] = useLazyQuery(GET_TODO); return ( <div> <h2>Todo</h2> <div> <p> <input ref={inputRef} /> {/* clickされたらgetTodoを実行する */} <button onClick={() => getTodo({ variables: { id: inputRef.current.value } })}> GET </button> </p> {loading && <p>...loading</p>} {error && <p>{error.message}</p>} {data && <p>ID: {data.todo.id}, Todo: {data.todo.type}</p>} </div> </div> ); } export default Todo;
- App.jsに反映します
src/App.jsimport React from 'react'; import { ApolloProvider } from '@apollo/client'; import client from './graphql/client'; import TodoList from './components/TodoList'; // importを追加 import Todo from './components/Todo'; function App() { return ( <ApolloProvider client={client}> <h1>Hello</h1> <TodoList /> {/* コンポーネントを追加 */} <Todo /> </ApolloProvider> ); } export default App;Mutationを実行する
- 実行するMutationを定義するファイルを作成します
- Todoを追加する
ADD_TODO
を定義します- 引数の書き方はQueryの時と同じです
src/query/mutation.jsimport { gql } from '@apollo/client'; export const ADD_TODO = gql` mutation AddTodo($type: String!) { addPlayer(type: $type) { id type } } `;useMutation
- コンポーネントからMutationを実行してみます
useMutation
から取得できるaddTodo
を呼び出すとMutationを実行できますsrc/components/AddTodo.jsimport React, { useRef } from 'react'; import { useMutation } from '@apollo/client'; import { ADD_TODO } from '../graphql/mutation'; function AddTodo() { const inputRef = useRef(null); const [addTodo, { loading, error }] = useMutation(ADD_TODO); return ( <div> <h2>AddTodo</h2> {loading && <p>...loading</p>} {error && <p>{error.message}</p>} <p> <input ref={inputRef} /> {/* クリックしたらaddTodoを実行する */} <button onClick={() => addTodo({ variables: { type: inputRef.current.value } })}> ADD </button> </p> </div> ); } export default AddTodo;
- App.jsに反映します
src/App.jsimport React from 'react'; import { ApolloProvider } from '@apollo/client'; import client from './graphql/client'; import TodoList from './components/TodoList'; import Todo from './components/Todo'; // importを追加 import AddTodo from './components/AddTodo'; function App() { return ( <ApolloProvider client={client}> <h1>Hello</h1> <TodoList /> <Todo /> {/* コンポーネントを追加 */} <AddTodo /> </ApolloProvider> ); } export default App;
- 最後におまけで、追加したTodoを画面に反映させたいのでTodoListを再取得するボタンを追加します
src/components/TodoList.jsimport React from 'react'; import { useQuery } from '@apollo/client'; import { GET_TODOS } from '../graphql/query'; function TodoList() { // refetchを追加 const { loading, error, data, refetch } = useQuery(GET_TODOS); if (loading) return <p>...loading</p>; if (error) return <p>{error.message}</p>; return ( <div> <h2>TodoList</h2> {/* クリックするとデータを再取得する */} <button onClick={() => refetch()}>REFETCH</button> {data.todos.map(todo => ( <p key={todo.id}>{todo.id}: {todo.type}</p> ))} </div> ); } export default TodoList;まとめ
- Aplloを使うとloadingの管理などもやってくれるため本当に便利ですね
- とりあえず
useQuery
,useLazyQuery
,useMutation
の3つが使えればだいたいのことはできると思います- これらを使った実装がとても簡単だと実感してもらえていれば幸いです