当状态变量改变时,铯折线不渲染

时间:2021-01-08 16:20:07

标签: reactjs cesium

我使用 ReactCesiumResium 作为 Cesium 包装器

代码:

import React,{useState,useEffect} from "react";
import { Viewer } from "resium";
import * as Resium from "resium";
import * as Cesium from 'cesium';
import flightData from "./data";
const terrainProvider = Cesium.createWorldTerrain();
const sleep = (ms) =>{
    return new Promise((res)=>{
      setTimeout(()=>res(),ms);
    })
}

const positions = [];
flightData.map(dataPoint=>{
    positions.push(dataPoint.longitude);
    positions.push(dataPoint.latitude);
    positions.push(dataPoint.height);
});

const ResiumComp=()=>{
    let viewer;
    const [posModel, setPosModel] = useState(null);
    const [airplaneUri, setAirplaneUri] = useState(null);
    const handleReady = tileset => {
        if (viewer) {
          //viewer.zoomTo(tileset);
        }
    };

    const airPlaneURI = async() => {
        const uri = await Cesium.IonResource.fromAssetId(246327)
        setAirplaneUri(uri);
    };

    const movePlane = async() =>{
        airPlaneURI();
        for(let i=0; i<flightData.length; i++){
            const dataPoint = flightData[i];
            const position = Cesium.Cartesian3.fromDegrees(dataPoint.longitude, dataPoint.latitude, dataPoint.height);
            setPosModel(position);
            await sleep(100);
        }
    }

    useEffect(()=>{
        Cesium.Ion.defaultAccessToken = process.env.REACT_APP_CESIUM_TOKEN;
        movePlane();
    },[]);

    return <Viewer
    full terrainProvider={terrainProvider}
    ref={e=>{
        viewer = e && e.cesiumElement;
    }}
    style={{
        position: "absolute",
        top: 0,
        left: 100,
        right: 0,
        bottom: 100,
      }}
    >
        {/* <Resium.Cesium3DTileset url={Cesium.IonResource.fromAssetId(5714)} onReady={handleReady}/> */}
        {
            flightData.map((dataPoint,idx)=>{
                const position = Cesium.Cartesian3.fromDegrees(dataPoint.longitude, dataPoint.latitude, dataPoint.height);
                return <>
                        <Resium.Entity 
                            key={`point-${idx}`}
                            name="Tokyo" 
                            description = {`Location: (${dataPoint.longitude}, ${dataPoint.latitude}, ${dataPoint.height})`}
                            position={position}
                        >
                            <Resium.PointGraphics pixelSize={10} />
                        </Resium.Entity>
                    </>
            })
        }
        {/* polyline */}
        <Resium.Entity>
            <Resium.PolylineGraphics
                show
                width={3}
                material={Cesium.Color.RED}
                positions={Cesium.Cartesian3.fromDegreesArrayHeights(positions)}
            />
        </Resium.Entity>
        {/* Model */}
        {
            (airplaneUri&&posModel)&&<Resium.Entity
                tracked 
                position={posModel}
            >
                <Resium.ModelGraphics
                    scale={1}
                    uri={airplaneUri}
                    minimumPixelSize={100}
                    runAnimations
                    show
                    color={Cesium.Color.WHITE}
                />
            </Resium.Entity>
        }
    </Viewer>
}
export default ResiumComp;

此处 PolylineGraphics 未呈现。当我检查代码时,我明白了,问题是由于状态变量的变化而出现的。

因此,当我注释掉 setPosModel(position); 行时,折线正在呈现。

更改以下功能代码

 const movePlane = async() =>{
        airPlaneURI();
        for(let i=0; i<flightData.length; i++){
            const dataPoint = flightData[i];
            const position = Cesium.Cartesian3.fromDegrees(dataPoint.longitude, dataPoint.latitude, dataPoint.height);

            // after commenting this line, there is no issue
            //setPosModel(position);
            await sleep(100);
        }
    }

折线图形在任何情况下都应该呈现,但我无法弄清楚。

Public git repositery link

1 个答案:

答案 0 :(得分:0)

这个问题与铯/resium无关,而是自身反应。

请注意,在您的 useEffect() 方法中,您调用 movePlane(),然后调用 setPosModel(position) - 一个状态更改函数,它将重新渲染应用程序,它将调用 useEffect() ...
知道我要去哪里了吗?

有多种解决方案可以阻止您的应用无限重新渲染。最简单的方法是遵循 react 建议并将 movePlane 包裹在 useCallback() 钩子中,如下所示:

const movePlane = useCallback(() => async() =>{
        airPlaneURI();
        for(let i=0; i<flightData.length; i++){
            const dataPoint = flightData[i];
            const position = Cesium.Cartesian3.fromDegrees(dataPoint.longitude, dataPoint.latitude, dataPoint.height);
        setPosModel(position);
        await sleep(100);
    }
}, [])

当然,您还必须将 movePlane 添加到 useEffect() 的依赖项数组中:

useEffect(()=>{
    Cesium.Ion.defaultAccessToken = process.env.REACT_APP_CESIUM_TOKEN;
    movePlane();
},[movePlane]);

旁注:您的代码需要考虑许多问题!
例如,为什么在 for 循环的每次迭代之后调用 setPosModel()?据我所知,flightData 是一个巨大的数组,你也应该修复它