reearth / resium

React components for 🌏 Cesium
https://resium.reearth.io
MIT License
704 stars 130 forks source link

Resium Entities not being removed/re-rendered from viewer once added #658

Open BeyondBelief96 opened 2 months ago

BeyondBelief96 commented 2 months ago

Hello everyone, I'm sure this is a common use case but can't find in the documentation how to handle this. I have a feature that allows user to toggle on airports by state. So I have an API request to fetches all airports in a given US state, and then renders an entity at the position of the airports. However when the user toggles this feature off, the entity points still remain visible on the cesium viewer. I'm not sure how to properly remove entities from the viewer once added. Can anyone help me? Here is the relevant code:

import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Entity, EntityDescription } from 'resium';
import { fetchAirportsByState } from '../../redux/slices/airportsSlice';
import { updateCurrentAirportEntityIds } from '../../redux/slices/entitiesSlice';
import { AppDispatch, RootState } from '../../redux/store';
import { mapAirportDataToCartesian3 } from '../../utility/utils';

const VisibleAirports: React.FC = () => {
  const {
    showAirports,
    visibleAirports,
    selectedState: selectedStateAirports,
  } = useSelector((state: RootState) => state.airport);

  const dispatch = useDispatch<AppDispatch>();

  useEffect(() => {
    dispatch(fetchAirportsByState(selectedStateAirports));
  }, [dispatch, selectedStateAirports]);

  useEffect(() => {
    if (!showAirports) {
      dispatch(updateCurrentAirportEntityIds([])); // Clear airport entity IDs in the store
    } else {
      const newEntityIds = visibleAirports.map((airport) => airport.GLOBAL_ID);
      dispatch(updateCurrentAirportEntityIds(newEntityIds)); // Update airport entity IDs in the store
    }
  }, [showAirports, visibleAirports, dispatch]);

  if (!showAirports) {
    return null;
  }

  return (
    <EntityDescription>
      {visibleAirports.map((airport) => {
        const position = mapAirportDataToCartesian3(airport);
        if (!position) return null;

        return <Entity key={airport.GLOBAL_ID} position={position} point={{ pixelSize: 10 }} />;
      })}
    </EntityDescription>
  );
};

export default VisibleAirports;

This component is a child of Resium's Viewer component.

BeyondBelief96 commented 2 months ago

Also note, I tried using the show property on entities instead and it still doesn't seem to re-render the entities when the boolean value passed to the show prop changes.

import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Entity } from 'resium';
import { fetchAirportsByState } from '../../redux/slices/airportsSlice';
import { updateCurrentAirportEntityIds } from '../../redux/slices/entitiesSlice';
import { AppDispatch, RootState } from '../../redux/store';
import { mapAirportDataToCartesian3 } from '../../utility/utils';

const VisibleAirports: React.FC = () => {
  const {
    showAirports,
    visibleAirports,
    selectedState: selectedStateAirports,
  } = useSelector((state: RootState) => state.airport);

  const dispatch = useDispatch<AppDispatch>();

  useEffect(() => {
    dispatch(fetchAirportsByState(selectedStateAirports));
  }, [dispatch, selectedStateAirports]);

  useEffect(() => {
    if (showAirports) {
      const newEntityIds = visibleAirports.map((airport) => airport.GLOBAL_ID);
      dispatch(updateCurrentAirportEntityIds(newEntityIds));
    } else {
      dispatch(updateCurrentAirportEntityIds([]));
    }
  }, [showAirports, visibleAirports, dispatch]);

  return (
    <>
      {visibleAirports.map((airport) => {
        const position = mapAirportDataToCartesian3(airport);
        if (!position) return null;

        return (
          <Entity
            key={airport.GLOBAL_ID}
            id={airport.GLOBAL_ID}
            position={position}
            point={{ pixelSize: 10 }}
            show={showAirports}
          />
        );
      })}
    </>
  );
};

export default VisibleAirports;
BeyondBelief96 commented 2 months ago

I've tried creating a basic bare bones vite/resium project like so:

import { Entity, Viewer } from 'resium';
import './App.css';
import { Cartesian3 } from 'cesium';
import { useState } from 'react';

function App() {
  const position = Cartesian3.fromDegrees(-74.0707383, 40.7117244, 100);
  const pointGraphics = { pixelSize: 20 };
  const [showEntity, setShowEntity] = useState(true);

  function handleToggle() {
    setShowEntity(!showEntity);
  }

  return (
    <div style={{ display: 'flex', height: '100vh' }}>
      <div style={{ width: '100px', backgroundColor: '#f0f0f0', padding: '10px' }}>
        <button onClick={handleToggle}>Toggle Entity</button>
      </div>
      <Viewer style={{ flexGrow: 1 }}>
        {showEntity && <Entity position={position} point={pointGraphics} />}
      </Viewer>
    </div>
  );
}

export default App;

And when the showEntity state is toggled, the entity never dissapears from the viewer. I can't find any documentation in resium on how to handle rendering/removing entities from being rendered....can anyone help here?