You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Resium配置terrainProvider后状态更新触发地图重绘闪烁如何解决

问题描述

搭建基于Resium的地图展示示例项目时,给组件绑定onClick、onMouseMove事件,事件回调仅执行独立状态的赋值操作,该状态未在任何位置被引用使用。测试发现只要为Viewer配置terrainProvider属性,状态更新就会触发整个地图重绘、UI闪烁;移除terrainProvider配置后异常消失。
当前使用技术栈:React 17、Resium 1.14.3(内置Cesium 1.86.1),复现代码如下:

import React, { useState } from "react";
import { Cartesian3, Color } from "cesium";
import { Viewer, Entity } from "resium";
import * as Cesium from 'cesium';

export default function App() {
    const [currentPos, setCurrentPos] = useState(null);

    const handleMouseClick = (e, t) => {
        setCurrentPos("xxx");
    }

    return (
        <Viewer full
            onClick={handleMouseClick}
            onMouseMove={handleMouseClick}
            // terrainProvider={new Cesium.CesiumTerrainProvider({ url: 'https://api.maptiler.com/tiles/terrain-quantized-mesh-v2/?key=xxxxxxx' })}
        >
            <Entity
                name="Tokyo"
                position={Cartesian3.fromDegrees(139.767052, 35.681167, 100)}
                point={{ pixelSize: 10, color: Color.RED }}
            />
        </Viewer>
    );
}
产生原因
  • 内联写在JSX属性上的new Cesium.CesiumTerrainProvider(...)会在组件每次重渲染时生成一个全新的实例,每次渲染传给terrainProvider prop的引用地址都不相同
  • Resium内部对Cesium实例类props做浅比较校验,检测到terrainProvider引用变化后,会自动销毁旧的地形提供者实例、挂载新实例,触发全量地形瓦片重新请求加载、场景整体重绘,外在表现就是UI闪烁
  • 未配置terrainProvider时不存在实例重建触发逻辑,因此不会出现重绘闪烁问题
解决方案

核心原则是保证Cesium实例的引用稳定性,避免无关重渲染触发实例重建,有两种常用实现方式:

  • 不需要响应组件状态的固定配置实例,直接移到组件外部初始化,整个应用生命周期仅创建一次实例
  • 配置依赖组件状态的实例,使用useMemo缓存,仅在配置项真正变化时才重新创建实例

修正后的代码示例:

import React, { useState, useMemo } from "react";
import { Cartesian3, Color } from "cesium";
import { Viewer, Entity } from "resium";
import * as Cesium from 'cesium';

// 固定地形配置直接移到组件外部,仅初始化一次
const terrainProvider = new Cesium.CesiumTerrainProvider({ 
  url: 'https://api.maptiler.com/tiles/terrain-quantized-mesh-v2/?key=xxxxxxx' 
});

export default function App() {
    const [currentPos, setCurrentPos] = useState(null);

    // 如果地形配置依赖组件内变量,用useMemo缓存,依赖数组仅放实际影响地形配置的变量
    // const terrainProvider = useMemo(() => new Cesium.CesiumTerrainProvider({
    //   url: 'https://api.maptiler.com/tiles/terrain-quantized-mesh-v2/?key=xxxxxxx'
    // }), [/* 地形url、授权key等配置变量 */]);

    const handleMouseClick = (e, t) => {
        setCurrentPos("xxx");
    }

    return (
        <Viewer full
            onClick={handleMouseClick}
            onMouseMove={handleMouseClick}
            terrainProvider={terrainProvider}
        >
            <Entity
                name="Tokyo"
                position={Cartesian3.fromDegrees(139.767052, 35.681167, 100)}
                point={{ pixelSize: 10, color: Color.RED }}
            />
        </Viewer>
    );
}

额外注意

所有Cesium非原始值类型的实例(包括影像图层、实体、图元、相机配置对象等),都不要直接内联写在JSX属性位置,否则重渲染时的引用变化都会触发Resium的实例重建逻辑,引发性能问题或渲染异常。


内容的提问来源于stack exchange,提问作者Sagi Mann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 21:03:19