当 props 没有改变时组件被重新渲染
Component getting re-rendered when props aren't changing
我正在展示一张使用 React.memo() 记忆的地图。我希望地图仅在道具更改时重新渲染,但即使道具不更改也会重新渲染。当 props 没有改变时,如何防止重新渲染?
地图:
const MapContainer = React.memo((props) => {
const [map, setMap] = useState();
var bounds = new props.google.maps.LatLngBounds();
const setMapObj = (mapProps, map) => {
setMap(map);
};
useDeepCompareEffect(() => {
if (props.markers.length === 1) {
bounds.extend(
new props.google.maps.LatLng(props.markers[0].lat, props.markers[0].lng)
);
bounds.extend(
new props.google.maps.LatLng(
props.markers[0].lat - 1,
props.markers[0].lng - 1
)
);
map && map.fitBounds(bounds);
return;
}
for (var i = 0; i < props.markers.length; i++) {
bounds.extend(
new props.google.maps.LatLng(props.markers[i].lat, props.markers[i].lng)
);
}
if (map) {
map.fitBounds(bounds);
}
}, [props.markers, map]);
return (
<div className={props.className}>
<Map
google={props.google}
style={{ borderRadius: "10px" }}
// center={{ lat: 59.913, lng: 10.75 }}
initialCenter={{ lat: 59.913, lng: 10.75 }}
onReady={setMapObj}
zoom={8}
>
{console.log("rendered")}
{props.markers.map((item, index) => {
if (item.lat && item.lng)
return (
<Marker key={index} position={{ lat: item.lat, lng: item.lng }} />
);
})}
</Map>
</div>
);
});
export default GoogleApiWrapper({
apiKey: "API_KEY",
})(MapContainer);
由于父组件很大,我只添加了我认为相关的部分。
地图的父级:
function Home() {
const [plants, setPlants] = useState([
{
name: "Plant 1",
id: uuidv4(),
location: "",
coords: {},
country: "",
isOffshore: false
},
]);
const isObjectEmpty = (obj) => {
for (var i in obj) return false;
return true;
};
const getMarkers = () => {
var temp = [];
for (var i = 0; i < plants.length; i++)
if (!isObjectEmpty(plants[i].coords)) temp.push(plants[i].coords);
return temp;
};
return (
<section/>
<CustomMap className="map" markers={getMarkers()} />
<section/>
)
}
- 备忘录没有做深度比较
- 每次回家都是re-render,地图也会是re-render。因为
您正在传递标记作为执行函数的结果
每次生成一个新的数组,一个新的引用,指向不同的
目的。这当然被备忘录视为触发
re-render。除了新数组,请记住
getMarkers 函数每次也是新的,指的是不同的
目的。对于函数,通常使用useCallback。
- 我建议使用 useMemo 钩子来修复和排除创建
一个新数组,相应地,一个对新对象的引用。和
因此,在不需要时将不会 re-rendering。
- 不要忘记在 useMemo 中包含依赖项。在你的情况下是
植物。
例子
const markers = useMemo(() => {
var temp = [];
for (var i = 0; i < plants.length; i++)
if (!isObjectEmpty(plants[i].coords)) temp.push(plants[i].coords);
return temp;
}, [plants]);
我正在展示一张使用 React.memo() 记忆的地图。我希望地图仅在道具更改时重新渲染,但即使道具不更改也会重新渲染。当 props 没有改变时,如何防止重新渲染?
地图:
const MapContainer = React.memo((props) => {
const [map, setMap] = useState();
var bounds = new props.google.maps.LatLngBounds();
const setMapObj = (mapProps, map) => {
setMap(map);
};
useDeepCompareEffect(() => {
if (props.markers.length === 1) {
bounds.extend(
new props.google.maps.LatLng(props.markers[0].lat, props.markers[0].lng)
);
bounds.extend(
new props.google.maps.LatLng(
props.markers[0].lat - 1,
props.markers[0].lng - 1
)
);
map && map.fitBounds(bounds);
return;
}
for (var i = 0; i < props.markers.length; i++) {
bounds.extend(
new props.google.maps.LatLng(props.markers[i].lat, props.markers[i].lng)
);
}
if (map) {
map.fitBounds(bounds);
}
}, [props.markers, map]);
return (
<div className={props.className}>
<Map
google={props.google}
style={{ borderRadius: "10px" }}
// center={{ lat: 59.913, lng: 10.75 }}
initialCenter={{ lat: 59.913, lng: 10.75 }}
onReady={setMapObj}
zoom={8}
>
{console.log("rendered")}
{props.markers.map((item, index) => {
if (item.lat && item.lng)
return (
<Marker key={index} position={{ lat: item.lat, lng: item.lng }} />
);
})}
</Map>
</div>
);
});
export default GoogleApiWrapper({
apiKey: "API_KEY",
})(MapContainer);
由于父组件很大,我只添加了我认为相关的部分。 地图的父级:
function Home() {
const [plants, setPlants] = useState([
{
name: "Plant 1",
id: uuidv4(),
location: "",
coords: {},
country: "",
isOffshore: false
},
]);
const isObjectEmpty = (obj) => {
for (var i in obj) return false;
return true;
};
const getMarkers = () => {
var temp = [];
for (var i = 0; i < plants.length; i++)
if (!isObjectEmpty(plants[i].coords)) temp.push(plants[i].coords);
return temp;
};
return (
<section/>
<CustomMap className="map" markers={getMarkers()} />
<section/>
)
}
- 备忘录没有做深度比较
- 每次回家都是re-render,地图也会是re-render。因为 您正在传递标记作为执行函数的结果 每次生成一个新的数组,一个新的引用,指向不同的 目的。这当然被备忘录视为触发 re-render。除了新数组,请记住 getMarkers 函数每次也是新的,指的是不同的 目的。对于函数,通常使用useCallback。
- 我建议使用 useMemo 钩子来修复和排除创建 一个新数组,相应地,一个对新对象的引用。和 因此,在不需要时将不会 re-rendering。
- 不要忘记在 useMemo 中包含依赖项。在你的情况下是 植物。
例子
const markers = useMemo(() => {
var temp = [];
for (var i = 0; i < plants.length; i++)
if (!isObjectEmpty(plants[i].coords)) temp.push(plants[i].coords);
return temp;
}, [plants]);