1. ndj

    Posted

    ndj
Changes in title
+【Gatsby.js, React】ページ遷移させたいときは navigate() を使う
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,135 @@
+こんにちは、ndj です。
+
+現在、勉強がてら `Gatsby.js` を使用して簡単なホームページを作成しています。
+ヘッダーに言語を選択できる `select` ボックスを作成して、選択した言語に合わせてページを遷移したいなと思ったのですが、ハマってしまったので備忘録として残しておきます。
+
+## 使用技術とバージョン情報
+
+- gatsby: 2.32.3
+- gatsby-source-microcms: 1.0.1
+- react-router-dom: 5.2.0
+- react: 16.12.0
+
+## 結論
+
+- `React` 標準で使用される、`this.props.history.push` ではなく、`gatsby` の `navigate()` を使用する。
+
+## やりたかったこと
+
+amazon など、グローバルに使用されているサービスってヘッダーに言語情報を選択できるようになっていますよね。
+
+![スクリーンショット 2021-02-23 231313.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485313/950e54ca-a894-7005-8d37-bfbe0fa48dd9.png)
+
+amazon みたいに、言語情報を選択したら、その言語のページに遷移できるようにしたいなと。
+
+## 試みたこと
+
+当初は、以下のように、 `<select>`タグ の `onChange` イベントハンドラで `this.props.history.push(e.target.value)` をして、ページを遷移しようとしていました。
+参考:[codesandbox.io: w031p82nr5](https://codesandbox.io/s/w031p82nr5?file=/src/index.js)
+
+また、**言語別の説明文は headlessCMS に保存しており、ページ生成の際に、`gatsby-node.js` の `createPage` で `<Home />` に context を渡す**。みたいな感じでページを生成しておりました。
+
+```header.js
+import React from 'react';
+import { useStaticQuery, Link, navigate } from 'gatsby';
+import { Switch, Route, BrowserRouter as Router, withRouter } from 'react-router-dom';
+import Home from '../pages/locale';
+
+class DropDown extends React.Component {
+ onChange = (e) => {
+ this.props.history.push(`/${e.target.value}`);
+ }
+ render() {
+ return (
+ <select onChange={this.onChange}>
+ <option value="ja">日本語</option>
+ <option value="en">English</option>
+ </select>
+ );
+ }
+}
+
+const Menu = withRouter(DropDown);
+
+export default function Header() {
+ return (
+ <Router>
+ <header className="header">
+ <nav>
+ <ul id="header-list">
+ <li>
+ <Menu />
+ </li>
+ <li>
+ <Link to="/">Install now</Link>
+ </li>
+ </ul>
+ </nav>
+
+ </header>
+
+ <Switch>
+ <Route path='/ja' render={() => <Home locale="ja" />} />
+ <Route path='/en' render={() => <Home locale="en" />} />
+ </Switch>
+ </Router>
+
+ );
+}
+```
+
+こんな感じでページ遷移を実現させたかったんですが、エラーが出る。。。
+
+```
+Uncaught TypeError: Cannot read property 'post' of undefined
+```
+
+## 原因っぽい部分
+
+エラー自体の原因は、以下の部分です。
+
+```js
+<Route path='/ja' render={() => <Home locale="ja" />} />
+```
+
+先述のように、言語別の説明文は headlessCMS に保存しており、ページ生成の際に、`gatsby-node.js` の `createPage` で `GraphQL query` を投げて、 `<Home />` に context を渡す。みたいな感じでページを生成しておりました。
+つまり、上記のコードだと `select` ボックスの選択肢が変化したときに context を渡せないので、エラーが出てたという感じです。
+
+なので、**ページ遷移の方法を工夫する必要がありそう**です。
+
+## this.props.history.push ではなく、navigate() を使用する
+
+`DropDown` の `onChange` の部分を以下のように変更します。
+`gatsby` に専用の function があるみたいです。
+参考:[gatsbyjs:How to use the navigate helper function](https://www.gatsbyjs.com/docs/reference/built-in-components/gatsby-link/#how-to-use-the-navigate-helper-function)
+参考:[stackoverflow: What's the equivalent of this.props.history.push in gatsby?](https://stackoverflow.com/questions/58677568/whats-the-equivalent-of-this-props-history-push-in-gatsby)
+
+```header.js
+class DropDown extends React.Component {
+ onChange = (e) => {
+ navigate(`/${e.target.value}`);
+ }
+ render() {
+ return (
+ <select onChange={this.onChange}>
+ <option value="ja">日本語</option>
+ <option value="en">English</option>
+ </select>
+ );
+ }
+}
+```
+
+## 最後に
+`gatsby` もさることながら、 `React` 自体の習熟度も低く解決に時間がかかってしまいましたが、コツコツやっていきたいと思います。
+また、今回解決方法を検索する際に積極的に英語のページを見るようにしましたが、翻訳機能様の存在とソースは全世界で共通なので頑張れば意外といけました。
+
+誤字脱字、技術的なご指摘などございましたら、コメントいただけますとありがたいです。
+ここまで読んでいただきありがとうございました。
+これからも巨人の肩に乗り続けます。
+
+## 参考
+[amazon](https://www.amazon.co.jp/)
+[codesandbox.io: w031p82nr5](https://codesandbox.io/s/w031p82nr5?file=/src/index.js)
+[gatsbyjs:How to use the navigate helper function](https://www.gatsbyjs.com/docs/reference/built-in-components/gatsby-link/#how-to-use-the-navigate-helper-function)
+[stackoverflow: What's the equivalent of this.props.history.push in gatsby?](https://stackoverflow.com/questions/58677568/whats-the-equivalent-of-this-props-history-push-in-gatsby)