53

Leafletを使用してアプリに取り組んでいます( react-leaflet経由)。Leaflet は DOM を直接操作します。react-leaflet ライブラリはそれを変更しません。React フレンドリーな方法で Leaflet マップを制御するために使用できる React コンポーネントを提供するだけです。

このアプリでは、いくつかの単純な要素を含む div であるカスタム マップ マーカーを使用したいと考えています。Leaflet でこれを行う方法は、マーカーのiconプロパティをDivIconに設定することです。これにより、カスタム HTML を設定できます。DivIcon のhtmlプロパティを HTML を含む文字列に設定することで、その内部 HTML を設定します。私の場合、その HTML を React コンポーネントからレンダリングしたいと考えています。

そのためにはReactDOMServer.renderToString()、マップ マーカー内に必要なコンポーネントを文字列にレンダリングし、それをhtmlDivIcon のプロパティとして設定するのが正しい方法のようです。

MyMarker.js:

import React, { Component } from 'react'
import { renderToString } from 'react-dom/server'
import { Marker } from 'react-leaflet'
import { divIcon } from 'leaflet'

import MarkerContents from './MarkerContents'

export class MyMarker extends Component {
  render() {
    const markerContents = renderToString(<MarkerContents data={this.props.data} />)
    const myDivIcon = divIcon({
      className: 'my-marker',
      html: markerContents
    })

    return (
      <Marker
        position={this.props.position}
        icon={myDivIcon} />
    )
  }
}

ただし、React docsによると:

この [renderToString] は、サーバー上でのみ使用する必要があります。

これは厳密なルールですか、それとも ReactDOM の DOM の効率的な管理を回避することを思いとどまらせることだけを意図したものですか?

私が求めていることを達成するための別の (より良い) 方法は考えられません。コメントやアイデアは大歓迎です。

4

4 に答える 4

17

古すぎる質問であることは承知していますが、まだ回答が得られていないため、私の考えを共有したいと思います。

私は同じものを使用してrenderToStringいましたが、ドキュメントではクライアント側で使用しないことを推奨しているため、react-dom'srenderメソッドを使用してカスタム コンポーネントを div にレンダリングするという別の方法で実現しました。

var myDiv = document.createElement('div');

ReactDOM.render(
  <MarkerContents data={this.props.data} />,
  myDiv
);

var myIcon = L.divIcon({ 
    iconSize: new L.Point(50, 50), 
    html: myDiv.innerHTML
});
于 2017-10-01T00:52:24.737 に答える
1

私はリーフレットでまったく同じ問題を抱えていて、ポータルで考えて問題を解決することになりました。

import React, { useEffect, useMemo,useState } from "react";
import ReactDOM from "react-dom";
import { useLeafletContext } from "@react-leaflet/core";
import * as L from "leaflet";

/**
 * @type { React.FC<{
 *    positionX?: number
 *    positionY?: number
 *    width?: number
 *    height?:number
 * }> }
 * */
const LeafletChild = ({ children, positionX=0, positionY=0, width, height }) => {
  const context = useLeafletContext();
  const [divElement] = useState(() => document.createElement("div"));
  const icon = useMemo(() => L.divIcon({ iconSize: new L.Point(height, width), html: divElement }), [height,width, divElement]);
  const marker = useMemo(() => L.marker([0,0], { icon }), [icon]);
  useEffect(()=>{
    marker.setLatLng([positionY, positionX])
  },[positionY,positionX, marker])

  useEffect(() => {
    const container = context.layerContainer || context.map;
    container.addLayer(marker);
    return () => container.removeLayer(marker);
  }, [context, marker]);
  return ReactDOM.createPortal(children, divElement);
};

どこかで...

<LeafletChild>
  <div onClick={()=>setSomeBool(!someBool)}>
    anything you want here like...{`${someBool}`}
  </div>
</LeafletChild>
于 2021-09-27T21:08:24.917 に答える