Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useCesium always returns an undefined viewer #672

Open
MatthewHerbst opened this issue Sep 4, 2024 · 6 comments
Open

useCesium always returns an undefined viewer #672

MatthewHerbst opened this issue Sep 4, 2024 · 6 comments

Comments

@MatthewHerbst
Copy link

MatthewHerbst commented Sep 4, 2024

Specs:

  • Resium: 1.18.2
  • React: 17.0.2
  • Node: 20.5.1
  • Server side rendering: no

Expected: viewer is defined once the globe has rendered
Actual: viewer is always undefined, even after the globe and other map layers have rendered
Related: #596

import { Moon, useCesium, Viewer } from "resium";

import { defaultImageryProvider } from "./defaultImageryProvider";
import { terrainProvider } from "./terrainProvider"'

function MyMap() {
  const { viewer } = useCesium();

  useEffect(() => {
      console.log("viewer", viewer); // Always `undefined`
  }, [viewer]);

  return (
          <Viewer
            animation={false}
            baseLayerPicker={false}
            fullscreenButton={false}
            geocoder={false}
            globe={globe}
            homeButton={false}
            imageryProvider={defaultImageryProvider}
            infoBox={false}
            navigationHelpButton={false}
            requestRenderMode={true}
            scene3DOnly={true}
            sceneModePicker={false}
            selectionIndicator={false}
            targetFrameRate={60}
            terrainProvider={terrainProvider}
            timeline={false}
        >
            <Moon show={false} />
        </ResiumViewer>
  );
}

Is there some extra setup needed somewhere to make this properly work?

@Fedec96
Copy link

Fedec96 commented Sep 12, 2024

Issue #596 might be related.

@MatthewHerbst
Copy link
Author

Issue #596 might be related.

Possible! We aren't using Next or SSR which is why I made is a separate issue

@www159
Copy link

www159 commented Nov 3, 2024

i have solved it with a strange way. only within the Viewer component does the Provider create the context, then useCesium() will return the right context property.
like this:

const HandlerComponent = () => {
  const { viewer } = useCesium();
  const setOsmBuildingsTileset = useSetAtom(atomOsmBuindingsTileset);
  console.log(viewer);
  useEffect(() => {
    createOsmBuildingsAsync().then((osmBuildingsTileset) => {
      setOsmBuildingsTileset(osmBuildingsTileset);
      viewer?.scene.primitives.add(osmBuildingsTileset);
    });
  }, []);
  return <></>;
};

function App() {
  // ANCHOR store
  const osmBuildingsTileset = useAtomValue(atomOsmBuindingsTileset);
  if (osmBuildingsTileset === undefined) return <>loading...</>;
  return (
    <>
      <Viewer full terrain={terrain} animation={false}>
        <Entity position={position} name="Tokyo">
          <PointGraphics pixelSize={10} />
          <EntityDescription>
            <h1>Hello, world.</h1>
            <p>JSX is available here!</p>
          </EntityDescription>
        </Entity>
        <CameraLookAt
          target={Cartesian3.fromDegrees(144.96007, -37.82249)}
          offset={new Cartesian3(0.0, -1500.0, 1200.0)}
        />
        <HandlerComponent />
      </Viewer>
    </>
  );
}

@MatthewHerbst
Copy link
Author

Interesting, makes some sense I guess but still a bit strange, would expect a context value to update regardless of where it's called from. Thanks for the solution!

@saadatali48
Copy link

const { viewer } = useCesium();
You can't use this in the parent component where Viewer is getting initialized.
viewer will be defined if you use useCesium() hook in child component of <Viewer>.

@fanchen4139
Copy link

fanchen4139 commented Jan 2, 2025

As a rule, we should use useCesium in Viewer tag.
if u want use it in the parent component, i have solved it with timer.
like this:

function App() {
  const cesiumRef = useRef<CesiumComponentRef<CesiuimViewer>>(null)
  const [viewer, setViewer] = useState<Cesium.Viewer>(null)
  
  const getViewer = (): Cesium.Viewer => {
    if (!viewer) {
      const viewerRef = cesiumRef.current.cesiumElement
      setViewer(viewerRef)
      return viewerRef
    } else {
      return viewer
    }
  }
  // get right context by timer
  useEffect(() => {
    const interval = setInterval(() => {
      if (!viewer) {
        getViewer()
      } else {
        clearInterval(interval)
      }
    }, 100);
    return () => {
      clearInterval(interval)
    }
  }, [viewer])
  
  const handleClick = useCallback(() => {
     console.log(viewer) // or getViewer(), you will get right property
  }, [])
  
  return (
    <>
      <ResiumViewer ref={cesiumRef} full terrain={terrain} animation={false} onClick={handleClick}>
        <Entity position={position} name="Tokyo">
          <PointGraphics pixelSize={10} />
          <EntityDescription>
            <h1>Hello, world.</h1>
            <p>JSX is available here!</p>
          </EntityDescription>
        </Entity>
        <CameraLookAt
          target={Cartesian3.fromDegrees(144.96007, -37.82249)}
          offset={new Cartesian3(0.0, -1500.0, 1200.0)}
        />
      </ResiumViewer>
    </>
  );
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants