【发布时间】:2022-08-14 15:58:59
【问题描述】:
由于某种原因,我的网络应用程序不是完全当状态改变时更新。
让我解释一下:我有一个 React-Leaflet Map,我希望在用户更改过滤条件时更新它。例如,更改某些Markers 出现的城市。为此,我构建了一个从端点加载一些 JSON 的后端,我的网络应用程序获取它,然后成功更新项目存储我需要的数据的数组。在此之后,确实将新标记添加到地图中。
什么不是更新的是我的MapContainer 的zoom 和center,尽管在安装组件时正确执行了处理此问题的功能。
因此,简而言之,在componentDidMount 内部,我获取数据,然后将其传递给state,用于填充和呈现我的地图。之后,如果用户按下筛选按钮并插入一个新城市我的componentDidUpdate 识别props 已更改,然后获取新数据。尽管如此,我的地图只会重新渲染添加新的标记没有设置新的缩放和新的中心。
有人会好心帮我解决这个问题吗?非常感谢提前。
import React from \"react\";
import { MapContainer, TileLayer } from \"react-leaflet\";
import MyMarker from \"./MyMarker\";
import \"./MapObject.css\";
/*
IMPORTANT: We are NOT taking into consideration the earth\'s curvature in
neither getCenter nor getZoom. This is only left as it is for
the time being because it is not mission critical
*/
// Function to calculate center of the map based on latitudes and longitudes in the array
function getCenter(json) {
// Array to store latitude and longitude
var lats = [];
var lngs = [];
const arr = Object.keys(json).map((key) => [key, json[key]]);
// Loop through the array to get latitude and longitude arrays
for (let i = 0; i < arr.length; i++) {
lats.push(arr[i][1].Latitude);
lngs.push(arr[i][1].Longitude);
}
const lat = lats.reduce((a, b) => a + b) / lats.length;
const lng = lngs.reduce((a, b) => a + b) / lngs.length;
return [lat, lng];
}
// Function to get the zoom level of the map based on the number of markers
function getZoom(json) {
// Array to store latitude and longitude
var lats = [];
var lngs = [];
const arr = Object.keys(json).map((key) => [key, json[key]]);
// Loop through the array to get latitude and longitude arrays
for (let i = 0; i < arr.length; i++) {
lats.push(arr[i][1].Latitude);
lngs.push(arr[i][1].Longitude);
}
const zoom = Math.floor(Math.log2(lats.length)) + 8;
return zoom;
}
export default class MapObject extends React.Component {
constructor(props) {
super(props);
this.state = {
map: null,
dataIsLoaded: false,
zoom: null,
position: [null, null],
items: [],
};
}
changePos(pos) {
this.setState({ position: pos });
const { map } = this.state;
if (map) map.flyTo(pos);
}
fetchData(filter, param) {
fetch(`https://my-backend-123.herokuapp.com/api/v1/${filter}/${param}`)
.then((res) => res.json())
.then((json) => {
this.setState(
{
items: json,
dataIsLoaded: true,
zoom: getZoom(json),
position: [getCenter(json)[0], getCenter(json)[1]],
},
() => {
console.log(\"State: \", this.state);
this.changePos(this.state.position);
}
);
});
console.log(
\"Fetched new data: \" +
\"DataisLoaded: \" +
this.state.dataIsLoaded +
\" \" +
\"Zoom: \" +
this.state.zoom +
\" \" +
\"Lat: \" +
this.state.position[0] +
\" \" +
\"Lng: \" +
this.state.position[1]
);
}
componentDidMount() {
this.fetchData(\"city\", this.props.filterValue);
}
componentDidUpdate(prevProps) {
if (prevProps.filterValue !== this.props.filterValue) {
this.fetchData(\"city\", this.props.filterValue);
//MapContainer.setCenter([getCenter(this.state.items)[0], getCenter(this.state.items)[1]]);
}
}
render() {
// Logic to show skeleton loader while data is still loading from the server
const { dataIsLoaded, items } = this.state;
console.log(\"Rendering!\");
if (!dataIsLoaded)
return (
<div className=\"bg-white p-2 h-160 sm:p-4 rounded-2xl shadow-lg flex flex-col sm:flex-row gap-5 select-none\">
<div className=\"h-full sm:h-full sm:w-full rounded-xl bg-gray-200 animate-pulse\"></div>
</div>
);
// Logic to show map and markers if data is loaded
return (
<div>
<MapContainer
id=\"mapId\"
whenCreated={(map) => this.setState({ map })}
attributionControl={true} // remove Leaflet attribution control
center={this.state.position}
zoom={this.state.zoom}
scrollWheelZoom={false}
>
<TileLayer
attribution=\'© <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors\'
url=\"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png\"
/>
{this.state.map}
{items.map((item, index) => (
<div key={index}>
<MyMarker
name={item.Name}
city={item.City}
prov={item.Province}
lat={item.Latitude}
lng={item.Longitude}
phone={item[\"Phone Number\"]}
/>
</div>
))}
</MapContainer>
</div>
);
}
}
我在下面留下一个 GIF 来展示当前的行为。您还可以简单地注意到标记“消失”:这是因为新标记已在考虑新过滤器的情况下呈现,这就是为什么我随后手动缩小以显示新标记确实已经渲染了。
编辑: 我现在正在尝试实现this 解决方案,但到目前为止我还没有成功。
-
你使用什么版本的 react-leaflet?你能创建一个与来自后端的模拟数据相同的演示吗?
标签: reactjs leaflet react-leaflet react-state