Closed2

React + typescript + GoogleMapApi でInfoWindowの中にボタン作って、それ押したら店舗情報取得してuseStateに格納する

sunaosunao

めちゃくちゃ沼った。
そのまま溺れて召されても良いかなとも思った。
でも何とかエラーなしで動くコードになった。

  1. InfoWindowの中のカスタマイズは普通にHTMLが組み込める
  2. コンポーネントを組み込見たいので import { renderToString } from "react-dom/server"を使う
  3. styled-componentsでCustomeButton的なbuttonを作成して組み込んだら表示はできた
  4. しかし、onClickが発動しない
  5. InfoWindow内は普通のコンポーネント内の要素ではなくなるためonClick()関数が呼ばれないらしい
  6. buttonにidつけて、document.getElementByIdで取得しようとしても無理
  7. 最終手段としてReactDOM.renderを使ってコンポーネントをねじ込んで成功
  8. しかしReact18からはcreateRootを使えと言われるので書き直す
  9. でもcreateRootはtypescriptにまだ適応してないらしいので、ReactDom.createRootを使用する
  10. document.getElementByIdじゃなくてuseRef使ってaddEventListener("click", みたいにしてクリック要素復活させた
  11. と思ったら、useRefからのClickイベント取得は必要なかった。ReactDom.createRootをちゃんと書けばいい話だった。直接DOM操作してるからそりゃそうか。最初にClick要素が無効になったのが衝撃的過ぎて混乱していた
  12. とにかく完成!
sunaosunao

こんな感じ(一部抜粋)

const createMarker = (place: google.maps.places.PlaceResult) => {
    if (!place.geometry || !place.geometry.location) return;

    const marker = new google.maps.Marker({
      map: Map,
      position: place.geometry.location,
      title: place.name,
      label: place.name?.charAt(0),
      optimized: false,
    });

    const storeFix = () => {
      changeStoreSelect(place.name, id);
      console.log("店名は" + place.name);
    };

    infoWindows[0] = new google.maps.InfoWindow();

    // infoWindowのカスタマイズコンポーネント→これをcreateRoot使ってレンダリングする
    const CustomInfoContent = () => (
      <>
        <HeadingText>{place.name}</HeadingText>
        <Text>住所:{place.vicinity}</Text>
        <DivBox>{place.photos && place.photos.length > 0 ? <ImageBox w={"auto"} h={"auto"} maxh={"150px"} src={place.photos[0].getUrl()} /> : null}</DivBox>
        <CustomButton
          onClick={() => {
            storeFix();
          }}
        >
          決定
        </CustomButton>
      </>
    );

    // createRoot使ってレンダリングする。最終的にinfoWindowContentをぶち込む
    const infoWindowContent = document.createElement("div");
    const root = createRoot(infoWindowContent);
    root.render(<CustomInfoContent />);

    //マーカーをクリックしたときの処理
    google.maps.event.addListener(marker, "click", () => {
      // 2つ目があったら2つ目は閉じる
      if (infoWindows[1]) infoWindows[1].close();
      // 2つ目が存在しなかったら何もせず終了
      if (!infoWindows[0]) return;
      infoWindows[0].close();
      // ここでInfoWindowを呼び出す
      infoWindows[0].setContent(infoWindowContent);
      infoWindows[0].open(marker.getMap(), marker);
      console.log(place);
    });
  };
このスクラップは2023/11/11にクローズされました