Guide
Component Lifecycle
Section titled âComponent LifecycleâResium brings Reactâs component lifecycle to Cesium. The relationship between Cesium elements and Reactâs lifecycle is as follows:
- Render: Nothing is rendered, as a cesium element is not initialized yet.
- Initalize Cesium element: An Cesium element is initialized, and it is added to its parent if the parent exists.
- Re-render: After Cesium elementâs initalization, children of the component are rendered. DOM never be rendered except root components (Viewer and CesiumWidget).
- Update: Changed properties of the Cesium element are updated. If âCesium read-only propertiesâ are changed, the Cesium element will be reinitialized.
- Unmount: The Cesium element is destroyed.
Context and component availability
Section titled âContext and component availabilityâSome components provide some Cesium elements to children via Reactâs context API. Many components use the closest componentâs context. If the context does not exists, components are not rendered.
All components except root components have to be mounted inside root components. Root components are Viewer and CesiumWidget.
For example:
If Entity component is mounted under Viewer component, an Entity object is added to Viewer#entities.
<Viewer> <Entity /></Viewer>is equivalent to
const viewer = new Cesium.Viewer();const entity = new Cesium.Entity();
viewer.entities.add(entity);If Entity component is mounted under CustomDataSource component, an Entity object is added to CustomDataSource#entities. At that time, the CustomDataSource object is added to Viewer#dataSources. Of course CustomDataSource component should be under Viewer component.
<Viewer> <CustomDataSource> <Entity /> </CustomDataSource></Viewer>is equivalent to
const viewer = new Cesium.Viewer();const dataSource = new Cesium.CustomDataSource();const entity = new Cesium.Entity();
customDataSource.entities.add(entity);viewer.dataSources.add(dataSource);Such cases are also in other components. For details, refer to âAvailabilityâ in the document of each component.
Component location
Section titled âComponent locationâPlease place each component as close as possible under Viewer or CesiumWidget component to avoid extra rendering. Make component hierarchy shallow as possible.
Exception are:
Entity>*GraphicsEntity>EntityDescriptionScreenSpaceEventHandler>ScreenSpaceEventxCollection>xCustomDataSource>EntityGroundPrimitiveCollection>GroundPrimitive
e.g.: Scene > Camera or Camera > Entity is not recommended.
// not recomended<Viewer> <Scene> <Camera> <Entity /> </Camera> </Scene></Viewer>// recomended<Viewer> <Scene /> <Camera /> <Entity /></Viewer>Properties
Section titled âPropertiesâEach components of resium have 4 kinds of properties as bellow.
Cesium properties
Section titled âCesium propertiesââCesium propertyâ is a property derived from Cesium. Each properties are correspond to a property of the cesium element. All âcesium propertiesâ are variable, so when they are updated in React component, the corresponding properties will be updated seamlessly.
Cesium read-only properties
Section titled âCesium read-only propertiesââCesium read-only propertyâ is also a property derived from Cesium, but it is immutable. They are available only when initializing the element.
If âCesium read-only propsâ are changed in React component, the Cesium element will be destroyed and reinitialized. It can be a cause of performance deterioration. Please use carefully to avoid changing as much as possible.
For example, imageryProvider property of ImageryLayer component is a âCesium read-only propertyâ. So in the following code, ImageryLayer is reinitialized in every rendering time!
const Example = () => ( <Viewer> <ImageryLayer imageryProvider={ new ArcGisMapServerImageryProvider({ url: "//services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer", }) } /> </Viewer>);If imageryProvider property is constant, The following is recommended.
import { Viewer, ImageryLayer } from "resium";import { ArcGisMapServerImageryProvider } from "cesium";
const imageryProvider = new ArcGisMapServerImageryProvider({ url: "//services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer",});
const ExampleComponent = () => ( <Viewer> <ImageryLayer imageryProvider={imageryProvider} /> </Viewer>);If imageryProvider property is variable, use useMemo hooks:
import { useMemo } from "react";import { Viewer, ImageryLayer } from "resium";import { ArcGisMapServerImageryProvider } from "cesium";
const ExampleComponent = ({ url }) => { const imageryProvider = useMemo( () => new ArcGisMapServerImageryProvider({ url }), [url], );
return ( <Viewer> <ImageryLayer imageryProvider={imageryProvider} /> </Viewer> );};Cesium events
Section titled âCesium eventsââCesium eventâ is a event propery of Cesium element. It can be used in the same way as normal React component events.
They are renamed according to Reactâs custom. For example, Viewer#trackedEntityChanged => onTrackedEntityChange.
Other properties
Section titled âOther propertiesâSome components have convenient properties that do not exist in the Cesium element. They can be used in the same way as normal React component properties.
Accessing to a raw Cesium element
Section titled âAccessing to a raw Cesium elementâIf you want to access a raw Cesium element, you can use ref prop of components.
Ref is one of the concepts that comes up in React. To see more information, see the React documentation.
To know what is a Cesium element of each component, refer to âCesium elementâ in the document of each component.
Note: cesiumElement property in the ref object can be undefined: e.g. when an initialization error is occurred. Please check if itâs not undefined when using cesiumElement.
Way 1: useRef hooks (function component)
Section titled âWay 1: useRef hooks (function component)âFunction component:
import { useEffect, useRef } from "react";import { Viewer } from "resium";
const ExampleComponent = () => { const ref = useRef(null);
useEffect(() => { if (ref.current && ref.current.cesiumElement) { // ref.current.cesiumElement is Cesium's Viewer // DO SOMETHING } }, []);
return <Viewer ref={ref} />;};Function component in TypeScript:
import { useEffect, useRef } from "react";import { Viewer as CesiumViewer } from "cesium";import { Viewer, CesiumComponentRef } from "resium";
const ExampleComponent = () => { const ref = useRef<CesiumComponentRef<CesiumViewer>>(null);
useEffect(() => { if (ref.current?.cesiumElement) { // ref.current.cesiumElement is Cesium's Viewer // DO SOMETHING } }, []);
return <Viewer ref={ref} />;};Way 2: use a function (class component)
Section titled âWay 2: use a function (class component)âClass component:
import { Component } from "react";import { Viewer } from "resium";
class ExampleComponent extends Component { componentDidMount() { if (this.viewer) { // this.viewer is Cesium's Viewer // DO SOMETHING } }
render() { return ( <Viewer ref={(e) => { this.viewer = e ? e.cesiumElement : undefined; }} /> ); }}Class component in TypeScript:
import { Component } from "react";import { Viewer as CesiumViewer } from "cesium";import { Viewer } from "resium";
class ExampleComponent extends Component { private viewer: CesiumViewer | undefined;
componentDidMount() { if (this.viewer) { // this.viewer is Cesium's Viewer // DO SOMETHING } }
render() { return ( <Viewer ref={(e) => { this.viewer = e ? e.cesiumElement : undefined; }} /> ); }}Way 3: use createRef (class component)
Section titled âWay 3: use createRef (class component)âClass component:
import { Component, createRef } from "react";import { Viewer } from "resium";
class ExampleComponent extends Component { constructor(props) { super(props); this.ref = createRef(); }
componentDidMount() { if (this.ref.current && this.ref.current.cesiumElement) { // this.ref.current.cesiumElement is Cesium's Viewer // DO SOMETHING } }
render() { return <Viewer ref={this.ref} />; }}Class component in TypeScript:
import { Component, createRef } from "react";import { Viewer as CesiumViewer } from "cesium";import { Viewer } from "resium";
class ExampleComponent extends Component { private ref = createRef<CesiumViewer | undefined>();
componentDidMount() { if (this.ref.current?.cesiumElement) { // this.ref.current.cesiumElement is Cesium's Viewer // DO SOMETHING } }
render() { return <Viewer ref={this.ref} />; }}Accessing the Cesium element from descendant components
Section titled âAccessing the Cesium element from descendant componentsâInstead of a ref, components rendered inside Viewer / CesiumWidget can read the current Cesium objects from React context with the useCesium hook:
import { Viewer, useCesium } from "resium";
const Inner = () => { const { viewer, scene, camera } = useCesium(); // `viewer` is Cesium's Viewer, available because this runs inside <Viewer>. // DO SOMETHING return null;};
const ExampleComponent = () => ( <Viewer> <Inner /> </Viewer>);useCesium reads the closest Resium context, so it returns Cesium objects only when it is called from a component mounted under a root component (Viewer or CesiumWidget).
Calling useCesium in the same component that renders <Viewer> (i.e. the parent) returns an empty object, because the context provider lives inside Viewer. In that case the values will always be undefined. To fix this, move the logic into a child component as shown above, or use a ref instead.
Limitations
Section titled âLimitationsâ- Server side rendering is not supported. Cesium can be rendered only in web browsers.
- React Native is not supported. Resium runs only with
react-dom, as Cesium depends on APIs of web browsers (DOM, WebGL, Web Worker and so on).