简体   繁体   中英

How to use React useContext with leaflet routing machine and react leaflet?

I'm trying to use a useContext hook inside a react-leaflet controlComponent but I have an error when my context fires the update function.

I use a react-leaflet controlComponent because of leaflet routing machine. I think the code + the error are better than word:

MainBoard.tsx

export const CartographyContext: React.Context<CartographyContextType> = React.createContext<CartographyContextType>({ positions: [] });
...

const routeSummaryValueContext = React.useMemo(
  () => ({ routeSummary, setRouteSummary }),
  [routeSummary]
);

const elevationProfileValueContext = React.useMemo(
  () => ({ elevationProfile, setElevationProfile }),
  [elevationProfile]
);

........

<CartographyContext.Provider value={{ positions, elevationProfileValueContext, routeSummaryValueContext, positionsValueContext, addPosition, changePosition }}>
.........
<RoutingMachine
   orsOptions={{
        ....
   }} />
..........
</CartographyContext.Provider>

RoutingMachine.tsx:

const CreateRoutineMachineLayer = (props: any) => {
    const geoService = new GeoLocalisationService();
    const cartographyContext: CartographyContextType = React.useContext<CartographyContextType>(CartographyContext);
    const [routes, setRoutes] = React.useState<any[]>();

    React.useEffect(() => {
        if (routes) {
             //The line which cause the error
cartographyContext.elevationProfileValueContext.setElevationProfile(geoService.getElevationProfile(decodePolyline(routes[0].geometry, true)));
            const summary: RouteSummary = {
                ascent: routes[0].routeSummary.ascent,
                descent: routes[0].routeSummary.descent,
                distance: routes[0].routeSummary.distance,
                estimatedDuration: routes[0].routeSummary.duration
            }
            cartographyContext.routeSummaryValueContext.setRouteSummary(summary);
        }
    }, [routes]);

    const { orsOptions } = props;

    const instance = L.Routing.control({
        router: new OpenRouteRouter(orsOptions),
        lineOptions: {
            styles: [{ color: "#3933ff", weight: 4 }],
            extendToWaypoints: true,
            missingRouteTolerance: 0
        },
        routeWhileDragging: true,
        autoRoute: true,
        geocoder: new geocoder.Geocoder(),

    }).on('routesfound', (e) => {
        setRoutes(e.routes);
    });

    useMapEvents({
        click: (e: L.LeafletMouseEvent) => {
            if (instance.getWaypoints().length === 2 && instance.getWaypoints()[0].latLng == null) {
                instance.spliceWaypoints(0, 1, new L.Routing.Waypoint(e.latlng, null, {}));
            } else if (instance.getWaypoints().length === 2 && instance.getWaypoints()[1].latLng == null) {
                instance.spliceWaypoints(1, 1, new L.Routing.Waypoint(e.latlng, null, {}));
            } else {
                instance.spliceWaypoints(instance.getWaypoints().length, 0, new L.Routing.Waypoint(e.latlng, null, {}));
            }
        }
    });


    return instance;
};

const RoutingMachine = createControlComponent(CreateRoutineMachineLayer);

error:

g: React has detected a change in the order of Hooks called by ForwardRef(LeafComponent). This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks

   Previous render            Next render
   ------------------------------------------------------
1. useContext                 useContext
2. useRef                     useRef
3. useContext                 useRef
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


..............
Uncaught Error: Rendered fewer hooks than expected. This may be caused by an accidental early return statement.

I clearly doing something wrong here but I haven't found yet.

Thank you Kind regards

Ok I found the good implementation:

const RoutingMachine: React.FC<RoutingMachineProps> = (props) => {
    //const RoutineMachine = (props: any) => {
    const geoService = new GeoLocalisationService();
    const cartographyContext: CartographyContextType = React.useContext<CartographyContextType>(CartographyContext);
    const [instance, setInstance] = React.useState<any>();
    const [alreadyDisplayed, setAlreadyDisplayed] = React.useState(false);

    const { orsOptions } = props;

    const map = useMap();

    //const instance = L.Routing.control({
    React.useEffect(() => {
        const instance = L.Routing.control({
            router: new OpenRouteRouter(orsOptions),
            lineOptions: {
                styles: [{ color: "#3933ff", weight: 4 }],
                extendToWaypoints: true,
                missingRouteTolerance: 0
            },
            routeWhileDragging: true,
            autoRoute: true,
            geocoder: (L.Control as any).Geocoder.google({
                apiKey: GOOGLE.googleMapApiKey,
            }),

        }).on('routesfound', (e) => {
            const routes = e.routes;
            cartographyContext.setElevationProfile(geoService.getElevationProfile(decodePolyline(routes[0].geometry, true)));
            const summary: RouteSummary = {
                ascent: routes[0].routeSummary.ascent,
                descent: routes[0].routeSummary.descent,
                distance: routes[0].routeSummary.distance,
                estimatedDuration: routes[0].routeSummary.duration
            }
            cartographyContext.setRouteSummary(summary);
        })
        setInstance(instance);
        instance.addTo(map);
    }, []);

    useMapEvents({
        click: (e: L.LeafletMouseEvent) => {
            if (instance) {
                if (instance.getWaypoints().length === 2 && instance.getWaypoints()[0].latLng == null) {
                    instance.spliceWaypoints(0, 1, new L.Routing.Waypoint(e.latlng, null, {}));
                } else if (instance.getWaypoints().length === 2 && instance.getWaypoints()[1].latLng == null) {
                    instance.spliceWaypoints(1, 1, new L.Routing.Waypoint(e.latlng, null, {}));
                } else {
                    instance.spliceWaypoints(instance.getWaypoints().length, 0, new L.Routing.Waypoint(e.latlng, null, {}));
                }
            }
        }
    });

    return null;
};


export default RoutingMachine;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM