tohokuaikiのチラシの裏

技術的ネタとか。

ReactとGoogleMaps APIを使って地図表示させるとページ遷移した時に読み込みエラーが出る件

前提

Script Loaderとしてこのパッケージ使っています。 www.npmjs.com

この現象に困っちゃって、このパッケージ使ってるかな?とか思って生でローディングする方法にしようかと思ってしまった。直ってよかった。

症状

google.maps.marker.AdvancedMarkerElement が無いって言われる。ブラウザにエラー画面が表示される。

  1. 検索フォームでPlaces APIを使って場所を検索させる。
  2. Suggestionで出てきた項目を選択すると、次のページに遷移してマーカーで場所を表示
  3. TypeError: Cannot read properties of undefined (reading 'AdvancedMarkerElement') が表示される。
  4. なんでなん?と思ってブラウザリロードするとちゃんと表示される。

もちろん、marker Libraryはロード指定している。こんな感じ。

            <Wrapper
                apiKey={GOOGLE_MAP_API_KEY}
                version="beta"
                libraries={['marker']}
                render={render}
            >
            </Wrapper>

デバッグコンソールから Google maps places API must be loaded. って言われる。

これ使っています。 www.npmjs.com

  1. さっきの検索結果画面をリロードするとちゃんと表示されるので、「よしよし」とか思う。
  2. ブラウザバックで検索ページに戻ると、Places APIで作った検索候補Widgetが動いてなさげ。「場所を入力」ってPlaceholderが出てない。当然入力を始めてもインクリメンタルなサジェスチョンは出てこない。デバッグコンソール見ると、Google maps places API must be loaded. って出てる。。
  3. くっそー、ロードしているはずやねん…って思ってブラウザリロードすると直る。やっぱreact-google-autocomplete使ってるなら読み込みしてるやん。
import  { usePlacesWidget } from "react-google-autocomplete";

const GOOGLE_MAP_API_KEY: string = process.env.NEXT_PUBLIC_GMAP_API_KEY || ""

export default function Search() {
    const { ref } = usePlacesWidget<HTMLInputElement>({
        apiKey: GOOGLE_MAP_API_KEY,
        onPlaceSelected: (place) => {
            console.log(place);
        },
        options: {
            types: ["train_station"],
            componentRestrictions: { country: "JP" },
        },
    });
    return <input type="text" ref={ref} />
}

対応策

そのページで使わなくても、遷移するページの先に必要としているGoogleMaps Libraryも読み込んでおく。

さっきのコードでいうと、

            <Wrapper
                apiKey={GOOGLE_MAP_API_KEY}
                version="beta"
                libraries={['marker', 'places']}
                render={render}
            >
            </Wrapper>
export default function Search() {
    const { ref } = usePlacesWidget<HTMLInputElement>({
        apiKey: GOOGLE_MAP_API_KEY,
        onPlaceSelected: (place) => {
            console.log(place);
        },
        options: {
            types: ["train_station"],
            componentRestrictions: { country: "JP" },
        },
        libraries={['marker', 'places']}
    });
    return <input type="text" ref={ref} />
}

ってlibrariesをその先のページの分も指定する。結局一連のサービスで使っているもの全部指定しておけばいいんじゃないかな。なんでなんやろね。Reactが先読み込みしてるからなんかな?