简体   繁体   English

使用 useEffect 通过更新 state 来触发重新渲染,但不能在依赖数组中包含 state?

[英]Using useEffect to trigger a re-render by updating state, but cannot have state in dependency array?

function Map({latitude, longitude, markers}: MapProps) {

    const [currentZoom, setCurrentZoom] = useState(14);
    const sizeRef = useRef(null);

    useEffect(() => {
        const height = sizeRef.current.clientHeight;
        const width = sizeRef.current.clientWidth;
        const zoom = calculateZoomLevel(markers, height, width);
        setCurrentZoom(zoom);
    }, []);

    function onMapChange({zoom}: ChangeEventValue) {
        if (currentZoom !== zoom) {
            setCurrentZoom(zoom);
        }
    }

    return (
        <div ref={sizeRef}>
            <GoogleMapReact
                defaultCenter={{
                    lat: latitude,
                    lng: longitude
                }}
                zoom={currentZoom}
                onChange={onMapChange}
            >
                markers.map(function(marker) {
                    return (<Marker name={marker.name}/>
                });
            </GoogleMapReact>
        </div>
    );
}

I am using google-map-react with my web app and I am trying to calculate the zoom such that all the map markers are visible on the map, the calculateZoomLevel function uses the google-map-react API and requires the dimensions of the map in order to calculate the required zoom level. I am using google-map-react with my web app and I am trying to calculate the zoom such that all the map markers are visible on the map, the calculateZoomLevel function uses the google-map-react API and requires the dimensions of the map为了计算所需的缩放级别。 Since I am using server-side rendering I must wait until the React component has mounted until I am able retrieve the dimensions of the map.由于我使用的是服务器端渲染,因此我必须等到 React 组件已安装,直到我能够检索 map 的尺寸。 I cannot use the window.innerHeight/Width property.我不能使用window.innerHeight/Width属性。

Therefore, in theory, I must initially render the page with a default zoom level for the map, then once it is mounted I can retrieve the component dimensions, calculate the intended zoom level and then trigger a re-render of the map.因此,理论上,我必须首先使用 map 的默认缩放级别渲染页面,然后一旦安装,我可以检索组件尺寸,计算预期的缩放级别,然后触发 map 的重新渲染。 I am using functional components along with useEffect in order to try and achieve this.我正在使用功能组件和useEffect来尝试实现这一目标。

THIS DOES NOT WORK这不起作用

const [currentZoom, setCurrentZoom] = useState(14);

useEffect(() => {
    const height = sizeRef.current.clientHeight;
    const width = sizeRef.current.clientWidth;
    const zoom = calculateZoomLevel(markers, height, width);
    setCurrentZoom(zoom);
}, []);

HOWEVER THIS DOES然而这确实

const [currentZoom, setCurrentZoom] = useState(14);

useEffect(() => {
    const height = sizeRef.current.clientHeight;
    const width = sizeRef.current.clientWidth;
    const zoom = calculateZoomLevel(markers, height, width);
    setCurrentZoom(zoom);
}, [currentZoom]);

This would be fine, however the problem is that now useEffect is triggered every time that the zoom level is changed on the map (ie: when onMapChange is called).这很好,但问题是现在每次在useEffect上更改缩放级别时都会触发 useEffect(即:调用onMapChange时)。 When I have an empty dependency array, the useEffect runs once after initial render, but does not properly trigger the a re-render with the updated zoom level which was just calculated.当我有一个空的依赖数组时, useEffect在初始渲染后运行一次,但没有正确触发使用刚刚计算的更新缩放级别的重新渲染。 It seems that I have to have the currentZoom state inside the dependency array for the changes to propagate, but I still have to preserve the functionality of allowing the user to change the zoom on the map.似乎我必须在依赖数组中currentZoom state 才能传播更改,但我仍然必须保留允许用户更改 map 缩放的功能。

You should put currentZoom in Ref你应该把 currentZoom 放在 Ref

  <GoogleMapReact
            defaultCenter={{
                lat: latitude,
                lng: longitude
            }}
            zoom={currentZoom.current}
            onChange={onMapChange}
        >

Note: setState runs asynchronously, ex: currentZoom = 14 while useEffect setting the currentZoom state.注意:setState 异步运行,例如:currentZoom = 14 而 useEffect 设置 currentZoom state。 the GoogleMapReact renders but the currentZoom state is still 14 since setting state is not done yet GoogleMapReact 渲染,但当前缩放 state 仍然是 14,因为设置 state 尚未完成

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM