使用i18n更改语言时,使用react传单实时更新工具提示



由于react传单,我目前正在显示一个带有GeoJSON组件的Map。我还在一些国家和城市上空悬停时显示一些工具提示(例如,当我悬停在法国时,工具提示显示"法国"(。我还使用i18n进行国际化。国际化适用于国家/地区的工具提示,它们是实时更新的。

我有一个函数updateDisplay,可以在缩放更改时在国家的GeoJson组件或城市的Marker列表之间切换。

问题是,当我切换语言时,它适用于整个页面,但不适用于城市工具提示。它们只有在我缩放时才会更新(因此在调用updateDisplay时(。

我会有预期的行为:无论缩放如何,当我切换语言时,我都希望城市工具提示实时更新。

我希望我已经明确了

这是我的代码:

/**
* Display a Leaflet Map, containing a GeoJson object, or a list of Markers, depending on the zoom
*/
export default function CustomMap(): ReactElement {
const { t }: { t: TFunction } = useTranslation();
const countryToString = (countries: string[]): string => countries.map(c => t(c)).join(", ");

// Contains the json containing the polygons of the countries
const data: geojson.FeatureCollection = geoJsonData as geojson.FeatureCollection;
let geoJson: JSX.Element = <GeoJSON
key='my-geojson'
data={data}
style={() => ({
color: '#4a83ec',
weight: 1,
fillColor: "#1a1d62",
fillOpacity: 0.25,
})}
onEachFeature={(feature: geojson.Feature<geojson.GeometryObject>, layer: Layer) => {
layer.on({
'mouseover': (e: LeafletMouseEvent) => {
const country = countries[e.target.feature.properties.adm0_a3];
layer.bindTooltip(countryToString(country.tooltip as string[]));
layer.openTooltip(country.latlng);
},
'mouseout': () => {
layer.unbindTooltip();
layer.closeTooltip();
},
});
}}
/>
// Contains a list of marker for the cities
const cityMarkers: JSX.Element[] = cities.map(
(
c: position,
i: number
) => {
return (
// Here are the tooltips that doesn't update in real time, when we switch language
// FIX ME
<Marker key={c.latlng.lat + c.latlng.lng} position={c.latlng}>
<Tooltip>{t(c.tooltip as string)}</Tooltip>
</Marker>
);
}
);
const [state, setState] = useState<state>({
zoom: 3,
display: geoJson,
});

// Update on zoom change
function onZoom(e: LeafletMouseEvent): void {
const zoom = e.target._zoom;
const newDisplay = updateDisplay(zoom);
setState({
...state,
zoom,
display: newDisplay,
});
}
// Called on every zoom change, in order to display either the GeoJson, or the cities Marker
function updateDisplay(zoom: number): Marker[] | any {
if (zoom >= 4) {
return cityMarkers;
} else {
return geoJson;
}
}

return (
<Map
style={{ height: "500px" }}
center={[54.370138916189596, -29.918133437500003]}
zoom={state.zoom}
onZoomend={onZoom}
>
<TileLayer url="https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw" />
{state.display}
</Map>
);
}

您也可以在此处查看:https://github.com/TheTisiboth/WebCV/blob/WIP/src/components/customMap.tsx
它在分支WIP 上

您可以执行以下操作来克服此问题:

  1. 如果添加了标记,则创建一个布尔标志以保存在内存中
  2. 使用本地传单代码而不是react'leaflet的包装在地图上添加标记。

    • 如果添加了标记并缩放>=4,则将标志设置为true
    • 如果缩放<4删除标记以显示国家/地区,将标志设置为false
  3. 当语言发生变化时,如果缩放大于4并且添加了标记,则删除以前的标记,使用新的工具提示添加新的标记

您可以通过持有对映射实例的引用来实现所有这些。

这是你需要的全部代码,(部分城市,删除了标记(:

import React, { useState, ReactElement } from "react";
import { useTranslation } from "react-i18next";
import { Map, Marker, TileLayer, GeoJSON } from "react-leaflet";
import geoJsonData from "../assets/geoJsonData.json";
import { LatLngLiteral, Layer, LeafletMouseEvent } from "leaflet";
import geojson from "geojson";
import { TFunction } from "i18next";
import L from "leaflet";
interface position {
latlng: LatLngLiteral;
tooltip: string;
}
interface state {
markers: position[];
zoom: number;
display: position[] | any;
geoJson: JSX.Element;
countries: { [key: string]: position };
}
/**
* Display a Leaflet Map, containing a GeoJson object, or a list of Markers, depending on the zoom
*/
export default function CustomMap(): ReactElement {
const mapRef: any = React.useRef();
const { t, i18n }: { t: TFunction; i18n: any } = useTranslation();
const [markersAdded, setMarkersAdded] = useState(false);
i18n.on("languageChanged", (lng: any) => {
if (lng) {
const map = mapRef.current;
if (map && map.leafletElement.getZoom() >= 4 && markersAdded) {
map.leafletElement.eachLayer(function (layer: L.Layer) {
if (layer instanceof L.Marker) map.leafletElement.removeLayer(layer);
});
state.markers.map((c: position, i: number) => {
L.marker(c.latlng)
.addTo(map.leafletElement)
.bindTooltip(t(c.tooltip));
});
}
}
});
// const countryToString = (countries: string[]): string => countries.join(", ");
// List of position and label of tooltip for the GeoJson object, for each country
const countries: { [key: string]: position } = {
DEU: {
latlng: {
lat: 51.0834196,
lng: 10.4234469,
},
tooltip: "travel.germany",
},
CZE: {
latlng: {
lat: 49.667628,
lng: 15.326962,
},
tooltip: "travel.tchequie",
},
BEL: {
latlng: {
lat: 50.6402809,
lng: 4.6667145,
},
tooltip: "travel.belgium",
},
};
// List of position and tooltip for the cities Markers
const cities: position[] = [
{
latlng: {
lat: 48.13825988769531,
lng: 11.584508895874023,
},
tooltip: "travel.munich",
},
{
latlng: {
lat: 52.51763153076172,
lng: 13.40965747833252,
},
tooltip: "travel.berlin",
},
{
// greece
latlng: {
lat: 37.99076843261719,
lng: 23.74122428894043,
},
tooltip: "travel.athens",
},
{
// greece
latlng: {
lat: 37.938621520996094,
lng: 22.92695426940918,
},
tooltip: "travel.corinth",
},
];
// Contains the json containing the polygons of the countries
const data: geojson.FeatureCollection = geoJsonData as geojson.FeatureCollection;
let geoJson: JSX.Element = (
<GeoJSON
key='my-geojson'
data={data}
style={() => ({
color: "#4a83ec",
weight: 1,
fillColor: "#1a1d62",
fillOpacity: 0.25,
})}
// PROBLEM : does not update the tooltips when we switch languages
// FIX ME
onEachFeature={(
feature: geojson.Feature<geojson.GeometryObject>,
layer: Layer
) => {
layer.on({
mouseover: (e: LeafletMouseEvent) => {
const country =
state.countries[e.target.feature.properties.adm0_a3];
layer.bindTooltip(t(country?.tooltip));
layer.openTooltip(country?.latlng);
},
mouseout: () => {
layer.unbindTooltip();
layer.closeTooltip();
},
});
}}
/>
);
const [state, setState] = useState<state>({
markers: cities,
zoom: 3,
geoJson: geoJson,
display: geoJson,
countries: countries,
});
// Update on zoom change
function onZoom(e: LeafletMouseEvent): void {
const zoom = e.target._zoom;
const newDisplay = updateDisplay(zoom);
setState({
...state,
zoom,
display: newDisplay,
});
}
// Called on every zoom change, in order to display either the GeoJson, or the cities Marker
function updateDisplay(zoom: number): Marker[] | any {
const map = mapRef.current;
if (zoom >= 4) {
return state.markers.map((c: position, i: number) => {
console.log(t(c.tooltip));
if (map && !markersAdded) {
console.log(map.leafletElement);
L.marker(c.latlng)
.addTo(map.leafletElement)
.bindTooltip(t(c.tooltip));
setMarkersAdded(true);
}
});
} else {
map.leafletElement.eachLayer(function (layer: L.Layer) {
if (layer instanceof L.Marker) map.leafletElement.removeLayer(layer);
});
setMarkersAdded(false);
return state.geoJson;
}
}
return (
<Map
ref={mapRef}
style={{ height: "500px" }}
center={[54.370138916189596, -29.918133437500003]}
zoom={state.zoom}
onZoomend={onZoom}
>
<TileLayer url='https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw' />
{state.display}
</Map>
);
}

Eng:

"travel": {
"germany": "Munich, Berlin, Hambourg, Münster, Allemagne",
"munich": "Munchen",
"berlin": "Berlin",
"tchequie": "Tchéquie, Prague",
"belgium": "Belgique",
"athens": "Athènes",
"corinth": "Corinthe",
...
}

Fr:

"travel": {
"germany": "Munich, Berlin, Hamburg, Münster, Germany",
"munich": "Munich",
"berlin": "Berlin",
"tchequie": "Czech Republic, Prague",
"belgium": "Belgium",
"athens": "Athens",
"corinth": "Corinth",
...
}

通过分别重用标记移除代码块和标记添加代码块,可以使其更加干净。

最新更新