diff --git a/package.json b/package.json
index 39090a66a..d267f4acc 100644
--- a/package.json
+++ b/package.json
@@ -40,7 +40,8 @@
   },
   "peerDependencies": {
     "cesium": "1.x",
-    "react": ">=18.2.0"
+    "react": ">=18.2.0",
+    "react-dom": ">=18.2.0"
   },
   "devDependencies": {
     "@storybook/addon-essentials": "8.0.5",
@@ -56,7 +57,7 @@
     "@types/react": "18.2.73",
     "@vitejs/plugin-react": "4.2.1",
     "c8": "9.1.0",
-    "cesium": "1.107.2",
+    "cesium": "1.116.0",
     "eslint": "8.57.0",
     "eslint-config-reearth": "0.3.0",
     "globby": "14.0.1",
@@ -75,4 +76,4 @@
     "vitest": "1.4.0",
     "web-streams-polyfill": "4.0.0"
   }
-}
+}
\ No newline at end of file
diff --git a/src/Billboard/Billboard.ts b/src/Billboard/Billboard.ts
index 42f679859..a37f4cfbd 100644
--- a/src/Billboard/Billboard.ts
+++ b/src/Billboard/Billboard.ts
@@ -16,7 +16,7 @@ Only inside [BillboardCollection](/components/BillboardCollection) components.
 A billboard object will be attached to the parent BillboardCollection.
 */
 
-export type BillboardCesiumProps = PickCesiumProps<CesiumBillboard, typeof cesiumProps>;
+export type BillboardCesiumProps = PickCesiumProps<CesiumBillboard, typeof cesiumProps, "position">;
 
 export type BillboardOtherProps = EventProps<{
   collection: BillboardCollection;
diff --git a/src/Cesium3DTileset/Cesium3DTileset.stories.tsx b/src/Cesium3DTileset/Cesium3DTileset.stories.tsx
index 534b79147..216c1b01d 100644
--- a/src/Cesium3DTileset/Cesium3DTileset.stories.tsx
+++ b/src/Cesium3DTileset/Cesium3DTileset.stories.tsx
@@ -1,7 +1,7 @@
 import { action } from "@storybook/addon-actions";
 import { Meta, StoryObj } from "@storybook/react";
 import { Viewer as CesiumViewer, Cesium3DTileStyle, IonResource } from "cesium";
-import { useRef } from "react";
+import { useMemo, useRef } from "react";
 
 import { CesiumComponentRef } from "../core";
 import { events } from "../core/storybook";
@@ -44,18 +44,11 @@ export const Resource: Story = {
   render: args => {
     // eslint-disable-next-line react-hooks/rules-of-hooks
     const ref = useRef<CesiumComponentRef<CesiumViewer>>(null);
+    // eslint-disable-next-line react-hooks/rules-of-hooks
+    const url = useMemo(() => IonResource.fromAssetId(96188), []);
     return (
       <Viewer full ref={ref}>
-        <Cesium3DTileset
-          {...args}
-          url={IonResource.fromAssetId(96188)}
-          onAllTilesLoad={action("onAllTilesLoad")}
-          onInitialTilesLoad={action("onInitialTilesLoad")}
-          onTileFailed={action("onTileFailed")}
-          onTileLoad={action("onTileLoad")}
-          onTileUnload={action("onTileUnload")}
-          {...events}
-        />
+        <Cesium3DTileset {...args} url={url} />
       </Viewer>
     );
   },
diff --git a/src/Cesium3DTileset/Cesium3DTileset.ts b/src/Cesium3DTileset/Cesium3DTileset.ts
index 8bc0de3d3..32f256c34 100644
--- a/src/Cesium3DTileset/Cesium3DTileset.ts
+++ b/src/Cesium3DTileset/Cesium3DTileset.ts
@@ -11,6 +11,7 @@ import {
   PickCesiumProps,
   ConstructorOptions,
   Merge,
+  isPromise,
 } from "../core";
 
 /*
@@ -58,7 +59,6 @@ const cesiumProps = [
   "modelMatrix",
   "shadows",
   "maximumScreenSpaceError",
-  "maximumMemoryUsage",
   "cullRequestsWhileMoving",
   "cullRequestsWhileMovingMultiplier",
   "preloadWhenHidden",
@@ -110,6 +110,7 @@ const cesiumProps = [
   "outlineColor",
   "cacheBytes",
   "maximumCacheOverflowBytes",
+  "enableCollision",
 ] as const;
 
 const cesiumReadonlyProps = [
@@ -121,6 +122,7 @@ const cesiumReadonlyProps = [
   "modelForwardAxis",
   "projectTo2D",
   "enableShowOutline",
+  "enablePick",
 ] as const;
 
 export const cesiumEventProps = {
@@ -143,11 +145,7 @@ const Cesium3DTileset = createCesiumComponent<CesiumCesium3DTileset, Cesium3DTil
     const maybePromiseURL = props.url;
 
     let resultURL: Exclude<Cesium3DTilesetProps["url"], Promise<Resource>>;
-    if (
-      maybePromiseURL &&
-      typeof maybePromiseURL === "object" &&
-      typeof (maybePromiseURL as Promise<unknown>).then === "function"
-    ) {
+    if (isPromise(maybePromiseURL)) {
       resultURL = await maybePromiseURL;
     } else {
       resultURL = maybePromiseURL as typeof resultURL;
diff --git a/src/Entity/Entity.test.tsx b/src/Entity/Entity.test.tsx
index d364577ab..9cf5dad52 100644
--- a/src/Entity/Entity.test.tsx
+++ b/src/Entity/Entity.test.tsx
@@ -1,4 +1,4 @@
-import { render } from "@testing-library/react";
+import { render, waitFor } from "@testing-library/react";
 import { Entity as CesiumEntity } from "cesium";
 import { createRef } from "react";
 import { expectType, TypeEqual } from "ts-expect";
@@ -52,5 +52,7 @@ it("should unmount", () => {
     </Provider>,
   ).unmount();
 
-  expect(ctx.entityCollection?.remove).toBeCalledWith(expect.any(CesiumEntity));
+  waitFor(() => {
+    expect(ctx.entityCollection?.remove).toBeCalledWith(expect.any(CesiumEntity));
+  });
 });
diff --git a/src/Entity/Entity.ts b/src/Entity/Entity.ts
index b068b6c48..b7b011fda 100644
--- a/src/Entity/Entity.ts
+++ b/src/Entity/Entity.ts
@@ -1,7 +1,14 @@
 import { Entity as CesiumEntity } from "cesium";
 import { ReactNode } from "react";
 
-import { createCesiumComponent, EventProps, PickCesiumProps, Merge, EventTarget } from "../core";
+import {
+  createCesiumComponent,
+  EventProps,
+  PickCesiumProps,
+  Merge,
+  EventTarget,
+  RootComponentInternalProps,
+} from "../core";
 
 export type { EventTarget } from "../core";
 
@@ -75,13 +82,14 @@ export type EntityCesiumEvents = {
   onDefinitionChange?: () => void;
 };
 
-export type EntityOtherProps = EventProps<EventTarget> & {
-  children?: ReactNode;
-  /** If true, the entity will be selected. It works only inside Viewer not CesiumWidget. */
-  selected?: boolean;
-  /** If true, the entity will be tracked by the camera. It works only inside Viewer not CesiumWidget. */
-  tracked?: boolean;
-};
+export type EntityOtherProps = RootComponentInternalProps &
+  EventProps<EventTarget> & {
+    children?: ReactNode;
+    /** If true, the entity will be selected. It works only inside Viewer not CesiumWidget. */
+    selected?: boolean;
+    /** If true, the entity will be tracked by the camera. It works only inside Viewer not CesiumWidget. */
+    tracked?: boolean;
+  };
 
 export type EntityProps = EntityCesiumProps &
   EntityCesiumReadonlyProps &
@@ -164,9 +172,12 @@ const Entity = createCesiumComponent<CesiumEntity, EntityProps>({
       }
     }
   },
-  provide(element) {
+  provide(element, _ctx, props) {
     return {
       entity: element,
+      __$internal: {
+        onUpdate: props?.onUpdate,
+      },
     };
   },
   cesiumProps,
diff --git a/src/Globe/Globe.ts b/src/Globe/Globe.ts
index f3de72235..c55a839c4 100644
--- a/src/Globe/Globe.ts
+++ b/src/Globe/Globe.ts
@@ -1,6 +1,6 @@
 import { Globe as CesiumGlobe, TerrainProvider } from "cesium";
 
-import { createCesiumComponent, PickCesiumProps } from "../core";
+import { createCesiumComponent, isPromise, PickCesiumProps } from "../core";
 
 /*
 @summary
@@ -93,8 +93,6 @@ const cesiumProps = [
   "translucency",
   "undergroundColor",
   "undergroundColorAlphaByDistance",
-  "terrainExaggeration",
-  "terrainExaggerationRelativeHeight",
   "lambertDiffuseMultiplier",
   "atmosphereLightIntensity",
   "atmosphereRayleighCoefficient",
@@ -113,11 +111,7 @@ const Globe = createCesiumComponent<CesiumGlobe, GlobeProps>({
   update: async (elm, props) => {
     const maybePromiseTerrainProvider = props.terrainProvider;
     let resultTerrainProvider: TerrainProvider;
-    if (
-      maybePromiseTerrainProvider &&
-      typeof maybePromiseTerrainProvider === "object" &&
-      typeof (maybePromiseTerrainProvider as Promise<unknown>).then === "function"
-    ) {
+    if (isPromise(maybePromiseTerrainProvider)) {
       resultTerrainProvider = await maybePromiseTerrainProvider;
     } else {
       resultTerrainProvider = maybePromiseTerrainProvider as TerrainProvider;
diff --git a/src/GroundPrimitiveCollection/GroundPrimitiveCollection.ts b/src/GroundPrimitiveCollection/GroundPrimitiveCollection.ts
index b7e4a14ca..0e56cd189 100644
--- a/src/GroundPrimitiveCollection/GroundPrimitiveCollection.ts
+++ b/src/GroundPrimitiveCollection/GroundPrimitiveCollection.ts
@@ -29,7 +29,7 @@ export type GroundPrimitiveCollectionOtherProps = {
 export type GroundPrimitiveCollectionProps = GroundPrimitiveCollectionCesiumProps &
   GroundPrimitiveCollectionOtherProps;
 
-const cesiumProps = ["show", "destroyPrimitives"] as const;
+const cesiumProps = ["show", "destroyPrimitives", "primitiveAdded", "primitiveRemoved"] as const;
 
 const GroundPrimitiveCollection = createCesiumComponent<
   PrimitiveCollection,
diff --git a/src/ImageryLayer/ImageryLayer.ts b/src/ImageryLayer/ImageryLayer.ts
index caff28024..4f9ae4355 100644
--- a/src/ImageryLayer/ImageryLayer.ts
+++ b/src/ImageryLayer/ImageryLayer.ts
@@ -1,6 +1,12 @@
 import { ImageryLayer as CesiumImageryLayer, ImageryProvider } from "cesium";
 
-import { createCesiumComponent, PickCesiumProps, Merge, ConstructorOptions2 } from "../core";
+import {
+  createCesiumComponent,
+  PickCesiumProps,
+  Merge,
+  ConstructorOptions2,
+  isPromise,
+} from "../core";
 
 /*
 @summary
@@ -86,19 +92,30 @@ const ImageryLayer = createCesiumComponent<CesiumImageryLayer, ImageryLayerProps
   async create(context, props) {
     if (!context.imageryLayerCollection) return;
 
-    const maybePromise = props.imageryProvider;
-
-    let result: ImageryProvider;
-    if (
-      maybePromise &&
-      typeof maybePromise === "object" &&
-      typeof (maybePromise as Promise<unknown>).then === "function"
-    ) {
-      result = await maybePromise;
-    } else {
-      result = maybePromise as ImageryProvider;
+    const imageryProvider = isPromise(props.imageryProvider)
+      ? props.imageryProvider
+      : new Promise<ImageryProvider>(r => queueMicrotask(() => r(props.imageryProvider)));
+
+    const imageryLayerWaitingList = context.__$internal?.imageryLayerWaitingList?.slice();
+    context.__$internal?.imageryLayerWaitingList
+      ? context.__$internal.imageryLayerWaitingList.push(imageryProvider)
+      : undefined;
+
+    // Make sure keeping the order of imagery layer to specify the index correctly.
+    if (imageryLayerWaitingList) {
+      await Promise.all(imageryLayerWaitingList.filter(v => isPromise(v)));
+    }
+
+    const result: ImageryProvider = await imageryProvider;
+
+    // Remove the awaited result from the waiting list.
+    if (context.__$internal?.imageryLayerWaitingList) {
+      context.__$internal.imageryLayerWaitingList =
+        context.__$internal.imageryLayerWaitingList.filter(i => i !== imageryProvider);
     }
 
+    if (!result) return;
+
     const element = new CesiumImageryLayer(result, props);
     context.imageryLayerCollection.add(element, props.index);
     return element;
diff --git a/src/Label/Label.ts b/src/Label/Label.ts
index dea7d6765..c400e4cd7 100644
--- a/src/Label/Label.ts
+++ b/src/Label/Label.ts
@@ -16,7 +16,7 @@ Only inside [LabelCollection](/components/LabelCollection) component.
 A label object will be attached to the parent LabelCollection.
 */
 
-export type LabelCesiumProps = PickCesiumProps<CesiumLabel, typeof cesiumProps>;
+export type LabelCesiumProps = PickCesiumProps<CesiumLabel, typeof cesiumProps, "position">;
 
 export type LabelOtherProps = EventProps<{
   collection: LabelCollection;
diff --git a/src/Model/Model.ts b/src/Model/Model.ts
index 9acd76cec..cb68b7921 100644
--- a/src/Model/Model.ts
+++ b/src/Model/Model.ts
@@ -1,6 +1,6 @@
 import { Model as CesiumModel, Primitive, ModelNode, ColorBlendMode, Resource } from "cesium";
 
-import { createCesiumComponent, EventProps, PickCesiumProps, Merge } from "../core";
+import { createCesiumComponent, EventProps, PickCesiumProps, Merge, isPromise } from "../core";
 
 export type Target = Merge<CesiumModel, Parameters<(typeof CesiumModel)["fromGltfAsync"]>[0]>;
 
@@ -77,6 +77,7 @@ const cesiumReadonlyProps = [
   "readyEvent",
   "texturesReadyEvent",
   "gltfCallback",
+  "enablePick",
 ] as const;
 
 export const otherProps = ["onReady", "onError", "url"] as const;
@@ -88,11 +89,7 @@ const Model = createCesiumComponent<CesiumModel, ModelProps>({
     const maybePromiseURL = url;
 
     let resultURL: Exclude<ModelProps["url"], Promise<Resource>>;
-    if (
-      maybePromiseURL &&
-      typeof maybePromiseURL === "object" &&
-      typeof (maybePromiseURL as Promise<unknown>).then === "function"
-    ) {
+    if (isPromise(maybePromiseURL)) {
       resultURL = await maybePromiseURL;
     } else {
       resultURL = maybePromiseURL as typeof resultURL;
diff --git a/src/Scene/Scene.ts b/src/Scene/Scene.ts
index f762c3470..d9dda9d9a 100644
--- a/src/Scene/Scene.ts
+++ b/src/Scene/Scene.ts
@@ -108,6 +108,9 @@ const cesiumProps = [
   "msaaSamples",
   "splitPosition",
   "debugCommandFilter",
+  "verticalExaggeration",
+  "verticalExaggerationRelativeHeight",
+  "atmosphere",
 ] as const;
 
 export const cesiumEventProps = {
diff --git a/src/Viewer/Viewer.ts b/src/Viewer/Viewer.ts
index 5d2e0cbe4..642db1203 100644
--- a/src/Viewer/Viewer.ts
+++ b/src/Viewer/Viewer.ts
@@ -9,6 +9,7 @@ import {
   PickCesiumProps,
   Merge,
   RootComponentInternalProps,
+  isPromise,
 } from "../core";
 
 /*
@@ -139,11 +140,7 @@ const Viewer = createCesiumComponent<CesiumViewer, ViewerProps, EventManager>({
     if (!wrapper) return;
 
     let resultTerrainProvider: TerrainProvider;
-    if (
-      terrainProvider &&
-      typeof terrainProvider === "object" &&
-      typeof (terrainProvider as Promise<unknown>).then === "function"
-    ) {
+    if (isPromise(terrainProvider)) {
       resultTerrainProvider = await terrainProvider;
     } else {
       resultTerrainProvider = terrainProvider as TerrainProvider;
@@ -196,6 +193,7 @@ const Viewer = createCesiumComponent<CesiumViewer, ViewerProps, EventManager>({
       globe: element.scene.globe,
       __$internal: {
         onUpdate: props?.onUpdate,
+        imageryLayerWaitingList: [],
       },
       [eventManagerContextKey]: state,
     };
diff --git a/src/core/component.test.tsx b/src/core/component.test.tsx
index 264991637..c57d23258 100644
--- a/src/core/component.test.tsx
+++ b/src/core/component.test.tsx
@@ -74,8 +74,10 @@ describe("core/component", () => {
       </Provider>,
     ).unmount();
 
-    expect(destroy).toBeCalledWith("foobar", value, null, undefined);
-    expect(destroy).toBeCalledTimes(1);
+    waitFor(() => {
+      expect(destroy).toBeCalledWith("foobar", value, null, undefined);
+      expect(destroy).toBeCalledTimes(1);
+    });
   });
 
   it("should set cesium events after created", () => {
@@ -111,7 +113,7 @@ describe("core/component", () => {
     expect(cesiumElement.foo).toBe(10);
   });
 
-  it("should update cesium props", () => {
+  it("should update cesium props", async () => {
     const cesiumElement = {
       foo: 0,
     };
@@ -124,14 +126,18 @@ describe("core/component", () => {
 
     const { rerender } = render(<Component />);
 
-    expect(cesiumElement.foo).toBe(0);
+    await waitFor(() => {
+      expect(cesiumElement.foo).toBe(0);
+    });
 
     rerender(<Component foo={1} />);
 
-    expect(cesiumElement.foo).toBe(1);
+    await waitFor(() => {
+      expect(cesiumElement.foo).toBe(1);
+    });
   });
 
-  it("should update cesium events", () => {
+  it("should update cesium events", async () => {
     const cesiumElement = {
       foo: new Event(),
       bar: new Event(),
@@ -159,12 +165,14 @@ describe("core/component", () => {
 
     rerender(<Component bar={() => {}} hoge={() => {}} />);
 
-    expect(cesiumElement.foo.numberOfListeners).toBe(0);
-    expect(cesiumElement.bar.numberOfListeners).toBe(1);
-    expect(cesiumElement.hoge.numberOfListeners).toBe(1); // TODO
+    await waitFor(() => {
+      expect(cesiumElement.foo.numberOfListeners).toBe(0);
+      expect(cesiumElement.bar.numberOfListeners).toBe(1);
+      expect(cesiumElement.hoge.numberOfListeners).toBe(1); // TODO
+    });
   });
 
-  it("should remount when cesium read only props are updated", () => {
+  it("should remount when cesium read only props are updated", async () => {
     const cesiumElement = {
       foo: 0,
     };
@@ -186,18 +194,22 @@ describe("core/component", () => {
 
     const { rerender } = render(<Component foo={1} />);
 
-    expect(createFn).toBeCalledTimes(1);
-    expect(destroyFn).toBeCalledTimes(0);
-    expect(cesiumElement.foo).toBe(1);
+    await waitFor(() => {
+      expect(createFn).toBeCalledTimes(1);
+      expect(destroyFn).toBeCalledTimes(0);
+      expect(cesiumElement.foo).toBe(1);
+    });
 
     rerender(<Component foo={2} />);
 
-    expect(createFn).toBeCalledTimes(2);
-    expect(destroyFn).toBeCalledTimes(1);
-    expect(cesiumElement.foo).toBe(2);
+    waitFor(() => {
+      expect(createFn).toBeCalledTimes(2);
+      expect(destroyFn).toBeCalledTimes(1);
+      expect(cesiumElement.foo).toBe(2);
+    });
   });
 
-  it("should call update", () => {
+  it("should call update", async () => {
     const updateFn = vi.fn();
 
     const Component = createCesiumComponent<{ hoge: "hoge" }, { foo?: number }>({
@@ -212,8 +224,10 @@ describe("core/component", () => {
 
     rerender(<Component foo={1} />);
 
-    expect(updateFn).toBeCalledTimes(1);
-    expect(updateFn).toBeCalledWith({ hoge: "hoge", foo: 1 }, { foo: 1 }, {}, {});
+    await waitFor(() => {
+      expect(updateFn).toBeCalledTimes(1);
+      expect(updateFn).toBeCalledWith({ hoge: "hoge", foo: 1 }, { foo: 1 }, {}, {});
+    });
   });
 
   it("should provide context", () => {
@@ -280,8 +294,10 @@ describe("core/component", () => {
       </Provider>,
     );
 
-    expect(cesiumElement.foo).toBe(1);
-    expect(onUpdate).toBeCalledTimes(1);
+    waitFor(() => {
+      expect(cesiumElement.foo).toBe(1);
+      expect(onUpdate).toBeCalledTimes(1);
+    });
   });
 
   it("should render container", () => {
@@ -329,13 +345,15 @@ describe("core/component", () => {
       </Provider>,
     ).unmount();
 
-    expect(provideFn).toBeCalledWith(
-      expect.anything(),
-      expect.anything(),
-      expect.anything(),
-      state,
-    );
-    expect(destroyFn).toBeCalledWith(expect.anything(), expect.anything(), null, state);
+    waitFor(() => {
+      expect(provideFn).toBeCalledWith(
+        expect.anything(),
+        expect.anything(),
+        expect.anything(),
+        state,
+      );
+      expect(destroyFn).toBeCalledWith(expect.anything(), expect.anything(), null, state);
+    });
   });
 
   it("should not render when noChildren is true", () => {
diff --git a/src/core/component.tsx b/src/core/component.tsx
index 0a020c2cc..311ca3623 100644
--- a/src/core/component.tsx
+++ b/src/core/component.tsx
@@ -1,3 +1,4 @@
+import { ImageryProvider } from "cesium";
 import {
   forwardRef,
   HTMLAttributes,
@@ -35,6 +36,10 @@ export type RootComponentInternalProps = {
   onUpdate?: () => void;
 };
 
+export type RootComponentInternalValues = {
+  imageryLayerWaitingList?: (Promise<ImageryProvider> | ImageryProvider)[];
+};
+
 export const createCesiumComponent = <Element, Props extends {}, State = any>({
   renderContainer,
   noChildren,
diff --git a/src/core/context.ts b/src/core/context.ts
index 49c22b073..7675d9c0f 100644
--- a/src/core/context.ts
+++ b/src/core/context.ts
@@ -19,7 +19,7 @@ import {
 } from "cesium";
 import { createContext, useContext } from "react";
 
-import { RootComponentInternalProps } from "./component";
+import { RootComponentInternalProps, RootComponentInternalValues } from "./component";
 import EventManager, { eventManagerContextKey } from "./EventManager";
 
 export type ResiumContext = {
@@ -40,7 +40,7 @@ export type ResiumContext = {
   polylineCollection?: PolylineCollection;
   pointPrimitiveCollection?: PointPrimitiveCollection;
   cloudCollection?: CloudCollection;
-  __$internal?: RootComponentInternalProps;
+  __$internal?: RootComponentInternalProps & RootComponentInternalValues;
   [eventManagerContextKey]?: EventManager;
 };
 
diff --git a/src/core/hooks.ts b/src/core/hooks.ts
index f6089ec63..708113181 100644
--- a/src/core/hooks.ts
+++ b/src/core/hooks.ts
@@ -12,7 +12,7 @@ import {
 import { RootComponentInternalProps } from "./component";
 import { ResiumContext, useCesium } from "./context";
 import { EventManager, eventManagerContextKey, eventNames } from "./EventManager";
-import { includes, shallowEquals, isDestroyed } from "./util";
+import { includes, shallowEquals, isDestroyed, isPromise } from "./util";
 
 export type EventkeyMap<T, P> = { [K in keyof P]?: keyof T };
 
@@ -82,6 +82,7 @@ export const useCesiumComponent = <Element, Props extends RootComponentInternalP
   const wrapperRef = useRef<HTMLDivElement>(null);
   const stateRef = useRef<State>();
   const eventManager = ctx?.[eventManagerContextKey];
+  const mountReadyRef = useRef<Promise<void>>();
 
   // Update properties
   const updateProperties = useCallback(
@@ -135,11 +136,7 @@ export const useCesiumComponent = <Element, Props extends RootComponentInternalP
 
       if (update && mountedRef.current) {
         const maybePromise = update(element.current, props, prevProps.current, ctx);
-        if (
-          maybePromise &&
-          typeof maybePromise === "object" &&
-          typeof (maybePromise as Promise<void>).then === "function"
-        ) {
+        if (isPromise(maybePromise)) {
           await maybePromise;
         }
       }
@@ -157,8 +154,8 @@ export const useCesiumComponent = <Element, Props extends RootComponentInternalP
           );
         }
 
-        unmount();
-        mount();
+        await unmount();
+        mountReadyRef.current = mount();
       }
     },
     [], // eslint-disable-line react-hooks/exhaustive-deps
@@ -169,11 +166,7 @@ export const useCesiumComponent = <Element, Props extends RootComponentInternalP
     const maybePromise = create?.(ctx, initialProps.current, wrapperRef.current);
 
     let result: CreateReturnType<Element, State>;
-    if (
-      maybePromise &&
-      typeof maybePromise === "object" &&
-      typeof (maybePromise as Promise<unknown>).then === "function"
-    ) {
+    if (isPromise(maybePromise)) {
       result = await maybePromise;
     } else {
       result = maybePromise as CreateReturnType<Element, State>;
@@ -224,7 +217,12 @@ export const useCesiumComponent = <Element, Props extends RootComponentInternalP
     setMounted(true);
   }, []); // eslint-disable-line react-hooks/exhaustive-deps
 
-  const unmount = useCallback(() => {
+  const unmount = useCallback(async () => {
+    // Wait mount before unmount
+    if (mountReadyRef.current) {
+      await mountReadyRef.current;
+    }
+
     // Destroy cesium element
     if (element.current && destroy) {
       destroy(element.current, ctx, wrapperRef.current, stateRef.current);
@@ -257,24 +255,33 @@ export const useCesiumComponent = <Element, Props extends RootComponentInternalP
 
   // To prevent re-execution by hot loader, execute only once
   useLayoutEffect(() => {
-    mount();
-    return () => unmount();
+    mountReadyRef.current = mount();
+    return () => {
+      unmount();
+    };
   }, []); // eslint-disable-line react-hooks/exhaustive-deps
 
   // Update properties of cesium element
   useEffect(() => {
-    const propsWC = propsWithChildren(props);
-    if (mounted) {
-      if (!shallowEquals(propsWC, prevProps.current)) {
-        updateProperties(propsWC);
-        ctx.__$internal?.onUpdate?.();
+    const update = async () => {
+      if (mountReadyRef.current) {
+        await mountReadyRef.current;
       }
-    } else {
-      // first time
-      prevProps.current = propsWC;
-      initialProps.current = propsWC;
-      mountedRef.current = true;
-    }
+
+      const propsWC = propsWithChildren(props);
+      if (mounted) {
+        if (!shallowEquals(propsWC, prevProps.current)) {
+          await updateProperties(propsWC);
+          ctx.__$internal?.onUpdate?.();
+        }
+      } else {
+        // first time
+        prevProps.current = propsWC;
+        initialProps.current = propsWC;
+        mountedRef.current = true;
+      }
+    };
+    update();
   }, [ctx.__$internal, mounted, props, updateProperties]);
 
   // Expose cesium element
diff --git a/src/core/util.ts b/src/core/util.ts
index e5300f2d9..ffb069d33 100644
--- a/src/core/util.ts
+++ b/src/core/util.ts
@@ -1,10 +1,13 @@
 export function pick<T extends {}, K extends keyof T>(obj: T, keys?: K[]): Pick<T, K> {
   if (!keys) return {} as Pick<T, K>;
-  return entries(obj).reduce((a, [k, v]) => {
-    if (!includes(keys, k)) return a;
-    (a as any)[k] = v;
-    return a;
-  }, {} as Pick<T, K>);
+  return entries(obj).reduce(
+    (a, [k, v]) => {
+      if (!includes(keys, k)) return a;
+      (a as any)[k] = v;
+      return a;
+    },
+    {} as Pick<T, K>,
+  );
 }
 
 export function entries<T extends {}>(obj: T): [keyof T, T[keyof T]][] {
@@ -35,3 +38,12 @@ export function isDestroyable(d: any): d is Destroyable {
 export function isDestroyed(d: any) {
   return isDestroyable(d) && d.isDestroyed();
 }
+
+export function isPromise<T>(maybePromise: T | Promise<T>): maybePromise is Promise<T> {
+  return (
+    maybePromise &&
+    typeof maybePromise === "object" &&
+    "then" in maybePromise &&
+    typeof maybePromise.then === "function"
+  );
+}
diff --git a/src/core/utils.test.ts b/src/core/utils.test.ts
new file mode 100644
index 000000000..43dfe5bbd
--- /dev/null
+++ b/src/core/utils.test.ts
@@ -0,0 +1,8 @@
+import { expect, test } from "vitest";
+
+import { isPromise } from "./util";
+
+test("isPromise", () => {
+  expect(isPromise({})).toBeFalsy();
+  expect(isPromise(Promise.resolve(undefined))).toBeTruthy();
+});
diff --git a/yarn.lock b/yarn.lock
index 84fbad556..ebeac2530 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1426,36 +1426,37 @@
   resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
   integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
 
-"@cesium/engine@^3.0.1":
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/@cesium/engine/-/engine-3.0.1.tgz#c2663cbbc672f314a9bb4bea3b2517af301083fa"
-  integrity sha512-EDZLbW4xiPnJ+8iv91xK5oN72Qi9FB8EPQVc2dLB+WvxB5P4aHQJhjalA/mBWF/7+gdU77sGq5W+dLC9DF3b1A==
+"@cesium/engine@^9.0.0":
+  version "9.0.0"
+  resolved "https://registry.yarnpkg.com/@cesium/engine/-/engine-9.0.0.tgz#74573f52100ef84ba5fcde9cd1084c07f7fe2fa7"
+  integrity sha512-GIeBitHo1t6OwgWnxAsCoHuCcJEfdki2G0hbKfaP87r2EapbnDLBmfxZziscl1ksv7kQiQ6x2FOOSPuV9QFvhA==
   dependencies:
-    "@tweenjs/tween.js" "^21.0.0"
-    "@zip.js/zip.js" "2.4.x"
+    "@tweenjs/tween.js" "^23.1.1"
+    "@zip.js/zip.js" "^2.7.34"
     autolinker "^4.0.0"
     bitmap-sdf "^1.0.3"
     dompurify "^3.0.2"
+    draco3d "^1.5.1"
     earcut "^2.2.4"
     grapheme-splitter "^1.0.4"
     jsep "^1.3.8"
     kdbush "^4.0.1"
-    ktx-parse "^0.5.0"
+    ktx-parse "^0.7.0"
     lerc "^2.0.0"
     mersenne-twister "^1.1.0"
-    meshoptimizer "^0.19.0"
+    meshoptimizer "^0.20.0"
     pako "^2.0.4"
     protobufjs "^7.1.0"
     rbush "^3.0.1"
     topojson-client "^3.1.0"
     urijs "^1.19.7"
 
-"@cesium/widgets@^3.0.1":
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/@cesium/widgets/-/widgets-3.0.1.tgz#35ffc8e376f0b033e5a85a05e59c71b75f8baa87"
-  integrity sha512-VZokEo7oAR23XphiraXpGCp/XsccDIYq8QOMfPho3+kvtru49HOx6/ZDM3IyUXwVvshfrlE92P8c+67Nae4yDg==
+"@cesium/widgets@^6.0.0":
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/@cesium/widgets/-/widgets-6.0.0.tgz#be68f2b696bd6239cd37d63abd429e0608a9a0cb"
+  integrity sha512-zq0UqHji4PgPWTVdUB2hNb/FXe60eNDB11oW35/Z3REQfE4LBOkeR/RGck7hBOfYaubMiqwuwOw2lbl54OXzIA==
   dependencies:
-    "@cesium/engine" "^3.0.1"
+    "@cesium/engine" "^9.0.0"
     nosleep.js "^0.12.0"
 
 "@colors/colors@1.5.0":
@@ -2839,10 +2840,10 @@
   resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e"
   integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==
 
-"@tweenjs/tween.js@^21.0.0":
-  version "21.0.0"
-  resolved "https://registry.yarnpkg.com/@tweenjs/tween.js/-/tween.js-21.0.0.tgz#73f993c2d1de37b78b4c1246163e20bc6ae3b75e"
-  integrity sha512-qVfOiFh0U8ZSkLgA6tf7kj2MciqRbSCWaJZRwftVO7UbtVDNsZAXpWXqvCDtIefvjC83UJB+vHTDOGm5ibXjEA==
+"@tweenjs/tween.js@^23.1.1":
+  version "23.1.1"
+  resolved "https://registry.yarnpkg.com/@tweenjs/tween.js/-/tween.js-23.1.1.tgz#0ae28ed9c635805557f78c2626464018d5f1b5e2"
+  integrity sha512-ZpboH7pCPPeyBWKf8c7TJswtCEQObFo3bOBYalm99NzZarATALYCo5OhbCa/n4RQyJyHfhkdx+hNrdL5ByFYDw==
 
 "@types/argparse@1.0.38":
   version "1.0.38"
@@ -3464,10 +3465,10 @@
     "@types/emscripten" "^1.39.6"
     tslib "^1.13.0"
 
-"@zip.js/zip.js@2.4.x":
-  version "2.4.26"
-  resolved "https://registry.yarnpkg.com/@zip.js/zip.js/-/zip.js-2.4.26.tgz#b79bb2055dc6e185890ee01cdb710caba505d5b2"
-  integrity sha512-I9HBO3BHIxEMQmltmHM3iqUW6IHqi3gsL9wTSXvHTRpOrA6q2OxtR58EDSaOGjHhDVJ+wIOAxZyKq2x00AVmqw==
+"@zip.js/zip.js@^2.7.34":
+  version "2.7.40"
+  resolved "https://registry.yarnpkg.com/@zip.js/zip.js/-/zip.js-2.7.40.tgz#e53626cfe051119df97bf1672188b9f36dfe75b8"
+  integrity sha512-kSYwO0Wth6G66QM4CejZqG0nRhBsVVTaR18M/Ta8EcqcvaV0dYrnDDyKAstfy0V5+ejK4b9w5xc1W0ECATJTvA==
 
 accepts@~1.3.5, accepts@~1.3.8:
   version "1.3.8"
@@ -4041,13 +4042,13 @@ caniuse-lite@^1.0.30001587:
   resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz#93a3ee17a35aa6a9f0c6ef1b2ab49507d1ab9079"
   integrity sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==
 
-cesium@1.107.2:
-  version "1.107.2"
-  resolved "https://registry.yarnpkg.com/cesium/-/cesium-1.107.2.tgz#109d8d2a8bbf977d01f4a9ec5e051d865f9cca70"
-  integrity sha512-qQDVyY3ZORbfn/8LM4v7vPOZZBMyVBwxJsC0SAbGEOH6hVR+wEDHjBCzphSJFppmomy01+lS+PsA5wcNpWtOFw==
+cesium@1.116.0:
+  version "1.116.0"
+  resolved "https://registry.yarnpkg.com/cesium/-/cesium-1.116.0.tgz#34c025babb49dfc4eeb98f9c83c37094a2083388"
+  integrity sha512-RZOOMePztCVb74JU/DTCTfuha7xTsJtEm3FRZeMUXyZABeRhbYjT1GwtAtoaPPJ5/IoqNjLvZnTNJdnU3LVE5g==
   dependencies:
-    "@cesium/engine" "^3.0.1"
-    "@cesium/widgets" "^3.0.1"
+    "@cesium/engine" "^9.0.0"
+    "@cesium/widgets" "^6.0.0"
 
 chai@^4.3.10:
   version "4.4.1"
@@ -4603,6 +4604,11 @@ dotenv@^16.0.0:
   resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e"
   integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==
 
+draco3d@^1.5.1:
+  version "1.5.7"
+  resolved "https://registry.yarnpkg.com/draco3d/-/draco3d-1.5.7.tgz#94f9bce293eb8920c159dc91a4ce9124a9e899e0"
+  integrity sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==
+
 duplexify@^3.5.0, duplexify@^3.6.0:
   version "3.7.1"
   resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309"
@@ -6637,10 +6643,10 @@ kolorist@^1.8.0:
   resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.8.0.tgz#edddbbbc7894bc13302cdf740af6374d4a04743c"
   integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==
 
-ktx-parse@^0.5.0:
-  version "0.5.0"
-  resolved "https://registry.yarnpkg.com/ktx-parse/-/ktx-parse-0.5.0.tgz#b4025bbc73ac5386ac37e869de455eab915261bc"
-  integrity sha512-5IZrv5s1byUeDTIee1jjJQBiD5LPDB0w9pJJ0oT9BCKKJf16Tuj123vm1Ps0GOHSHmeWPgKM0zuViCVuTRpqaA==
+ktx-parse@^0.7.0:
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/ktx-parse/-/ktx-parse-0.7.0.tgz#65788a43a1a1c19c795ff26299e9318c16b436b2"
+  integrity sha512-naezun/2iiWrantwoRI9mw6E4iN41ggYzJSR9XAZzf6+rv+2Tb1yYN8VJhGsA0uptBexE0m4GDh+iiQhYpW+Qw==
 
 lazy-universal-dotenv@^4.0.0:
   version "4.0.0"
@@ -6882,10 +6888,10 @@ mersenne-twister@^1.1.0:
   resolved "https://registry.yarnpkg.com/mersenne-twister/-/mersenne-twister-1.1.0.tgz#f916618ee43d7179efcf641bec4531eb9670978a"
   integrity sha512-mUYWsMKNrm4lfygPkL3OfGzOPTR2DBlTkBNHM//F6hGp8cLThY897crAlk3/Jo17LEOOjQUrNAx6DvgO77QJkA==
 
-meshoptimizer@^0.19.0:
-  version "0.19.0"
-  resolved "https://registry.yarnpkg.com/meshoptimizer/-/meshoptimizer-0.19.0.tgz#1669e6d788ad3ffd238a65184e478355642ca979"
-  integrity sha512-58qz5Qc/6Geu8Ib3bBWERE5R7pM5ErrJVo16fAtu6ryxVaE3VAtM/u2vurDxaq8AGZ3yWxuM/DnylTga5a4XCQ==
+meshoptimizer@^0.20.0:
+  version "0.20.0"
+  resolved "https://registry.yarnpkg.com/meshoptimizer/-/meshoptimizer-0.20.0.tgz#890eaeafa2b5730a0c58770fdf3b1fe77b746bf5"
+  integrity sha512-olcJ1q+YVnjroRJpCL1Dj5aZxr2JMr2hRutMUwhuHZvpAL7SIZgOT6eMlFF4TbBGSR89tawE/gqB79J/LrW/Nw==
 
 methods@~1.1.2:
   version "1.1.2"