GatsbyJSではbuilding中はブラウザーと切り離されるためwindowメソッドからのlocation取得の手法が使えません(参考:CSS TRICKS - How to Get the Current Page URL in Gatsby)
そのためGatsbyJSにデフォルトで入っている機能を使って取得しないといけないため少しややこしいです。
最初は import { useLocation } from 'react-router-dom' から引っ張れるかなと思ったら上手くいかず。
※@react/routerではなく@reach/routerです。記載ミスのため修正しました。
propsのlocationを親要素から取り出す
GatsbyJSの公式サイト Location Data from Props に記載されているようにクライアントサイドのルーティングにはデフォルトで @reach/router @reach/router(公式ドキュメント)が使用されています。
したがってpropsにlocationが渡されていることになるのでこれを利用します。
これは自分のケースですがlayout.jsファイルからlocationを呼び出しそれを引っ張ってきました。
import React, {FC} from 'react'
// 省略
const Layout: FC = ({ location }) => {
return (
<div>
<Header pathname={location.pathname} />
</div>
)
}
import React from 'react'
// 省略
const Layout: FC<{pathname: string}> = ({ pathname }) => {
return (
<div>
{pathname === '/' && (
<div>
hogehoge
</div>
)}
</div>
)
}
上記のような形で引っ張ってこれました。
ちなみにlocationオブジェクトの中身は下のようになります。
{
hash: ""
host: "localhost:8000"
hostname: "localhost"
href: "http://localhost:8000/login/"
key: "initial"
origin: "http://localhost:8000"
pathname: "/login/"
port: "8000"
protocol: "http:"
search: ""
state: null
}
詰まったところ
最初からHeaderコンポーネントに{ location }を引っ張ってこようとしてずっとエラーが生じました
Property 'location' does not exist on type '{ children?: ReactNode; }'.ts(2339)
怒られた通りに色々やってみてもダメでわからなかったのですがすでに述べたように親コンポーネントであるlayout.tsxからlocationを引っ張ってきたことで解決しました。
冒頭でも述べたように @reach/router の挙動がもとにあります。
また、
import React, {FC} from 'react'
// 省略
const Layout: FC = ({ location }) => {
return (
<div>
<Header location={location} />
</div>
)
}
layoutコンポーネントから { location } をそのまま受け渡してHeaderコンポーネントのほうで { location } を受け取ろうとしても先のTypeエラーが生じてダメでした。
名前をlocation以外に変えて受け取る必要があります。
SSRでlocationを取得する方法
gatsby-ssr.jsでSSRメソッドが利用できるのでそれを利用して各コンポーネントにSSR処理でlocationを取得する方法があります。
ここはまだ模索中です。自分のコードではなくCSS TRICKS - How to Get the Current Page URL in Gatsby)からコードを引用させてもらいました。
const React = require('react');
const config = require('./gatsby-config');
exports.onRenderBody = ({ pathname, setHeadComponents }) => {
setHeadComponents([
<link rel="canonical" href={`${config.siteMetadata.siteURL}${pathname}`} />,
]);
};
onRenderBodyメソッドを利用することでグローバルにコンポーネントを追加することができます。
参考:Gatsby Server Rendering APIs
setHeadComponentsとは各ページのヘッダーにJSXをセットするためのメソッドです。
config.siteMetadata.siteURLはgatsby-config.jsで設定した siteMetadata {省略} のプロパティに記載したURLです。
pathnameはドメインとhttpプロトコルを含まないslugです
なぜか上手くいかず
TypeScriptの環境なのかなんなのかわかりませんでしたがlocalhost:8000上ではヘッダーにが表示されず。
わかり次第、追記します。
ただし、本記事とは無関係ですがとりあえずSSRを試すという意味合いで下のコードは走りました。(bodyタグにクラス名をSSRの処理で追加)
exports.onRenderBody = ({ setBodyAttributes }, pluginOptions) => {
setBodyAttributes({
className: "body-test-className",
})
}