こんにちは、ndj です。
現在、勉強がてら Gatsby.js
を使用して簡単なホームページを作成しています。
ヘッダーに言語を選択できる select
ボックスを作成して、選択した言語に合わせてページを遷移したいなと思ったのですが、ハマってしまったので備忘録として残しておきます。
(2021/03/01) 追記:navigate を使用する場合は、Router を使用しなくてもよいことがわかったので、「this.props.history.push ではなく、navigate() を使用する」のコード部分を修正。
使用技術とバージョン情報
- 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 など、グローバルに使用されているサービスってヘッダーに言語情報を選択できるようになっていますよね。
amazon みたいに、言語情報を選択したら、その言語のページに遷移できるようにしたいなと。
試みたこと
当初は、以下のように、 <select>
タグ の onChange
イベントハンドラで this.props.history.push(e.target.value)
をして、ページを遷移しようとしていました。
参考:codesandbox.io: w031p82nr5
また、言語別の説明文は headlessCMS に保存しており、ページ生成の際に、gatsby-node.js
の createPage
で <Home />
に context を渡す。みたいな感じでページを生成しておりました。
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
原因っぽい部分
エラー自体の原因は、以下の部分です。
<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
参考:stackoverflow: What's the equivalent of this.props.history.push in gatsby?
import { Link, navigate } from 'gatsby';
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>
);
}
}
export default function Header() {
return (
<React.Fragment>
<header className="header">
<nav>
<ul id="header-list">
<li>
<DropDown />
</li>
<li>
<Link to="/">Install now</Link>
</li>
</ul>
</nav>
</header>
</React.Fragment>
);
}
最後に
gatsby
もさることながら、 React
自体の習熟度も低く解決に時間がかかってしまいましたが、コツコツやっていきたいと思います。
また、今回解決方法を検索する際に積極的に英語のページを見るようにしましたが、翻訳機能様の存在とソースは全世界で共通なので頑張れば意外といけました。
誤字脱字、技術的なご指摘などございましたら、コメントいただけますとありがたいです。
ここまで読んでいただきありがとうございました。
これからも巨人の肩に乗り続けます。
参考
amazon
codesandbox.io: w031p82nr5
gatsbyjs:How to use the navigate helper function
stackoverflow: What's the equivalent of this.props.history.push in gatsby?