@@ -23,7 +23,15 @@ import {
2323 createGooglePhotorealistic3DTileset ,
2424} from "cesium" ;
2525import { pick } from "lodash-es" ;
26- import { MutableRefObject , useCallback , useEffect , useMemo , useRef , useState } from "react" ;
26+ import {
27+ MutableRefObject ,
28+ useCallback ,
29+ useEffect ,
30+ useLayoutEffect ,
31+ useMemo ,
32+ useRef ,
33+ useState ,
34+ } from "react" ;
2735import { CesiumComponentRef , useCesium } from "resium" ;
2836
2937import type {
@@ -490,12 +498,53 @@ export const useHooks = ({
490498
491499 const [ style , setStyle ] = useState < Cesium3DTileStyle > ( ) ;
492500 const { url, type, idProperty, googleMapApiKey, provider } = useData ( layer ) ;
501+ const cesiumIonAccessToken =
502+ typeof meta ?. cesiumIonAccessToken === "string" ? meta . cesiumIonAccessToken : undefined ;
493503 const shouldUseFeatureIndex = ! disableIndexingFeature && ! ! idProperty ;
494504
495505 const [ isTilesetReady , setIsTilesetReady ] = useState ( false ) ;
496506 const [ isTilesetCompReady , setIsTilesetCompReady ] = useState ( false ) ;
497507 const [ isTilesetRefReady , setIsTilesetRefReady ] = useState ( false ) ;
498508
509+ const reearthGooglePhotorealisticUrl = useMemo (
510+ ( ) =>
511+ customProvider ?. layers ?. providers ?. find (
512+ p => p . id === "reearth_google_photorealistic_3d_tiles" ,
513+ ) ?. url ,
514+ [ customProvider ] ,
515+ ) ;
516+
517+ const tilesetKey = useMemo (
518+ ( ) =>
519+ generateIDWithMD5 (
520+ JSON . stringify ( {
521+ type,
522+ url,
523+ tileset,
524+ provider,
525+ googleMapApiKey,
526+ reearthGooglePhotorealisticUrl,
527+ cesiumIonAccessToken :
528+ type === "osm-buildings" ||
529+ ( type === "google-photorealistic" && ( provider === "cesium-ion" || ! googleMapApiKey ) )
530+ ? cesiumIonAccessToken
531+ : undefined ,
532+ } ) ,
533+ ) ,
534+ [
535+ type ,
536+ url ,
537+ tileset ,
538+ provider ,
539+ googleMapApiKey ,
540+ reearthGooglePhotorealisticUrl ,
541+ cesiumIonAccessToken ,
542+ ] ,
543+ ) ;
544+ const currentTilesetKeyRef = useRef ( tilesetKey ) ;
545+ currentTilesetKeyRef . current = tilesetKey ;
546+ const tilesetRefKeyRef = useRef < string | undefined > ( undefined ) ;
547+
499548 const prevPlanes = useRef ( _planes ) ;
500549 const planes = useMemo ( ( ) => {
501550 if (
@@ -563,27 +612,46 @@ export const useHooks = ({
563612
564613 const ref = useCallback (
565614 ( tileset : CesiumComponentRef < Cesium3DTilesetType > | null ) => {
566- if ( tileset ?. cesiumElement ) {
567- attachTag ( tileset . cesiumElement , {
615+ const cesiumElement = tileset ?. cesiumElement ;
616+ if ( tilesetKey !== currentTilesetKeyRef . current ) {
617+ return ;
618+ }
619+ if ( cesiumElement ) {
620+ attachTag ( cesiumElement , {
568621 layerId : layer ?. id || id ,
569622 featureIndex : shouldUseFeatureIndex ? featureIndex : undefined ,
570623 appearanceType : "3dtiles" ,
571624 } ) ;
572625 }
573- if ( layer ?. id && tileset ?. cesiumElement ) {
574- ( tileset ?. cesiumElement as any ) [ layerIdField ] = layer . id ;
626+ if ( layer ?. id && cesiumElement ) {
627+ ( cesiumElement as any ) [ layerIdField ] = layer . id ;
575628 }
576- tilesetRef . current = tileset ?. cesiumElement ;
577- setIsTilesetRefReady ( ! ! tileset ?. cesiumElement ) ;
629+ tilesetRef . current = cesiumElement ;
630+ tilesetRefKeyRef . current = cesiumElement ? tilesetKey : undefined ;
631+ setIsTilesetRefReady ( ! ! cesiumElement ) ;
578632 } ,
579- [ id , layer ?. id , featureIndex , shouldUseFeatureIndex ] ,
633+ [ id , layer ?. id , featureIndex , shouldUseFeatureIndex , tilesetKey ] ,
580634 ) ;
581635
582636 const selectedFeatureIdsRef = useRef < string [ ] > ( [ ] ) ;
583637 const selectedFeatureColorRef = useRef ( selectedFeatureColor ) ;
584638 selectedFeatureColorRef . current = selectedFeatureColor ;
585639 const [ selectedFeatureColorMap ] = useState ( ( ) => new Map < string , Color > ( ) ) ;
586640
641+ // The Cesium3DTileset child remounts when tilesetKey changes, while this hook stays mounted.
642+ useLayoutEffect ( ( ) => {
643+ setIsTilesetCompReady ( false ) ;
644+ setIsTilesetReady ( false ) ;
645+ if ( tilesetRefKeyRef . current !== tilesetKey ) {
646+ tilesetRef . current = undefined ;
647+ tilesetRefKeyRef . current = undefined ;
648+ setIsTilesetRefReady ( false ) ;
649+ }
650+ featureIndex . records . clear ( ) ;
651+ selectedFeatureIdsRef . current = [ ] ;
652+ selectedFeatureColorMap . clear ( ) ;
653+ } , [ tilesetKey , featureIndex , selectedFeatureColorMap ] ) ;
654+
587655 useEffect ( ( ) => {
588656 if ( ! tilesetRef . current || ! shouldUseFeatureIndex || ! isTilesetReady ) return ;
589657 Object . assign ( tilesetRef . current , {
@@ -759,24 +827,21 @@ export const useHooks = ({
759827
760828 // For Re:Earth provider, use the custom URL from customProvider or layer data
761829 if ( provider === "reearth" ) {
762- // Try to get URL from customProvider first, then fall back to layer URL
763- const customUrl = customProvider ?. layers ?. providers ?. find (
764- p => p . id === "reearth_google_photorealistic_3d_tiles" ,
765- ) ?. url ;
766-
767- return customUrl || url || null ;
830+ return reearthGooglePhotorealisticUrl || url || null ;
768831 }
769832
770833 // Otherwise load via Google API key or Cesium Ion.
771834 const loadTileset = async ( ) : Promise < Resource > => {
772835 try {
773836 if ( provider === "cesium-ion" || ! googleMapApiKey ) {
774837 const resource = await IonResource . fromAssetId ( 2275207 , {
775- accessToken : meta ?. cesiumIonAccessToken as string | undefined ,
838+ accessToken : cesiumIonAccessToken ,
776839 } ) ;
777840 return resource ;
778841 }
779- const tileset = await createGooglePhotorealistic3DTileset ( { key : googleMapApiKey } ) ;
842+ const tileset = await createGooglePhotorealistic3DTileset ( {
843+ key : googleMapApiKey ,
844+ } ) ;
780845 return tileset . resource ;
781846 } catch ( error ) {
782847 console . error ( `Error loading Photorealistic 3D Tiles tileset: ${ error } ` ) ;
@@ -785,7 +850,15 @@ export const useHooks = ({
785850 } ;
786851
787852 return loadTileset ( ) ;
788- } , [ type , isVisible , googleMapApiKey , meta ?. cesiumIonAccessToken , provider , customProvider , url ] ) ;
853+ } , [
854+ type ,
855+ isVisible ,
856+ googleMapApiKey ,
857+ cesiumIonAccessToken ,
858+ provider ,
859+ reearthGooglePhotorealisticUrl ,
860+ url ,
861+ ] ) ;
789862
790863 const tilesetUrl = useMemo ( ( ) : string | Resource | Promise < Resource > | null => {
791864 if ( ! isVisible ) return null ;
@@ -803,7 +876,7 @@ export const useHooks = ({
803876 // OSM Buildings — only available via Cesium Ion.
804877 if ( type === "osm-buildings" ) {
805878 return IonResource . fromAssetId ( 96188 , {
806- accessToken : meta ?. cesiumIonAccessToken as string | undefined ,
879+ accessToken : cesiumIonAccessToken ,
807880 } ) ; // https://github.com/CesiumGS/cesium/blob/main/packages/engine/Source/Scene/createOsmBuildings.js#L53
808881 }
809882
@@ -813,7 +886,7 @@ export const useHooks = ({
813886 }
814887
815888 return null ;
816- } , [ type , isVisible , googleMapPhotorealisticResource , url , tileset , meta ?. cesiumIonAccessToken ] ) ;
889+ } , [ type , isVisible , googleMapPhotorealisticResource , url , tileset , cesiumIonAccessToken ] ) ;
817890
818891 const imageBasedLighting = useMemo ( ( ) => {
819892 if (
@@ -854,11 +927,29 @@ export const useHooks = ({
854927
855928 const handleReady = useCallback (
856929 ( tileset : Cesium3DTileset ) => {
930+ if ( tilesetKey !== currentTilesetKeyRef . current ) {
931+ return ;
932+ }
857933 setIsTilesetCompReady ( true ) ;
858934 onLayerFetch ?.( { properties : tileset . properties } ) ;
859935 onLayerLoad ?.( { layerId : layerIdRef . current } ) ;
860936 } ,
861- [ onLayerFetch , onLayerLoad ] ,
937+ [ onLayerFetch , onLayerLoad , tilesetKey ] ,
938+ ) ;
939+
940+ const handleError = useCallback (
941+ ( error : unknown ) => {
942+ if ( tilesetKey !== currentTilesetKeyRef . current ) {
943+ return ;
944+ }
945+ tilesetRef . current = undefined ;
946+ tilesetRefKeyRef . current = undefined ;
947+ setIsTilesetCompReady ( false ) ;
948+ setIsTilesetRefReady ( false ) ;
949+ setIsTilesetReady ( false ) ;
950+ console . error ( "Error loading Cesium 3D Tileset:" , error ) ;
951+ } ,
952+ [ tilesetKey ] ,
862953 ) ;
863954
864955 useEffect ( ( ) => {
@@ -874,6 +965,7 @@ export const useHooks = ({
874965 } , [ type , updateCredits ] ) ;
875966
876967 return {
968+ tilesetKey,
877969 tilesetUrl,
878970 ref,
879971 style,
@@ -883,5 +975,6 @@ export const useHooks = ({
883975 builtinBoxProps,
884976 imageBasedLighting,
885977 handleReady,
978+ handleError,
886979 } ;
887980} ;
0 commit comments