React-Leaflet: updating a marker's position every second fetching the coordinates from an .env file

75 Views Asked by At

I'm running a simple react-lefleat map on small http server running on an Arduino board and I would like to update a marker's position (my position) according to the coordinates extraced by the Arduino from a connected GPS board.

The whole thing should work like this:

  1. the Arduino takes the coordinates from the GPS and writes latidude and longitude in a .env file;
  2. the React-Leaflet App should update the markers's position every 1 or 2 seconds I use an .env file because when I run the build command (npm run build) the .env file remains outside the minimized .js files and thus it is easly accesible (and writable) from the Arduino side (the App stays on a SD card). I did use the setInterval method but works it only for six times (that is the fetching's output). Does someone have any idea on how to update only the component that renders the marker, let's say every 1 o 2 second? The component's code is this:
import React, { useState, useEffect } from "react";
import textfile from "./data.env";
import { Marker, Popup } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import L from 'leaflet';

import icon from 'leaflet/dist/images/marker-icon.png';
import iconShadow from 'leaflet/dist/images/marker-shadow.png';

//import ReadTxt from "./ReadTxt";
//import LetturaTxt from "./LetturaTxt";

let DefaultIcon = L.icon({
    iconUrl: icon,
    shadowUrl: iconShadow
});

L.Marker.prototype.options.icon = DefaultIcon;

function Interval() {
    const [text, setText] = useState(0);

    useEffect(() => {
        //Implementing the setInterval method
        const interval = setInterval(() => {
            fetch(textfile)
                .then((response) => response.text())
                .then((textContent) => {
                    setText(textContent);
                }, []);
        }, 1000);
        //Clearing the interval
        return () => clearInterval(interval);
    }, []);


    //var result = parseFloat(text);
    //console.log(text)
    if (text > 0) {
        console.log(text)
        return (
            <Marker position={[parseFloat(text), +11.000]}>
                <Popup>
                    A pretty CSS3 popup. <br /> Easily customizable.
                </Popup>
            </Marker>
        )
    }

};

export default Interval;

while the main code of the App is this:

//import React from "react";
import React, { useRef } from "react";
import { MapContainer, TileLayer, GeoJSON } from "react-leaflet";
import "leaflet/dist/leaflet.css";
//import Marcatore from "./Marcatore";
import { HashRouter } from "react-router-dom";
//import LetturaTxt from "./LetturaTxt";
import CTR from "./Provincie.json";
//import Interval2 from "./Interval2";
//import ImportJS from "./ImportJS";
import Interval from "./Interval";


function App() {
  const latitude = 43.000;
  const longitude = 11.000;
  const mapRef = useRef(null);

  return (
    <HashRouter>
      <MapContainer center={[latitude, longitude]} zoom={13} ref={mapRef} style={{ height: "99vh", width: "vw" }}>
        <div>
          <Interval />
        </div>
        <GeoJSON data={CTR} />
      </MapContainer>
    </HashRouter >
  );
}

export default App;

Thanks a lot in advance! Sebastian

1

There are 1 best solutions below

0
Sebastian Schweizer On

I finally found the solution, here is the code for the component:

import React, { useEffect } from "react";
//import textfile from "./data.env";
import { Marker, Popup } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import L from 'leaflet';
//import { Icon } from 'leaflet';
//import icon from 'leaflet/dist/images/icons8-location-off-40.png';
//import iconShadow from 'leaflet/dist/images/marker-shadow.png';
import Fetch from "./Fetch";

//import ReadTxt from "./ReadTxt";
//import LetturaTxt from "./LetturaTxt";

function GetIcon() {
    return L.icon({
        iconUrl: require("leaflet/dist/images/icons8-location-off-40.png"),
        iconSize: [36,36],
        iconAnchor : [18,18],
    });
}

/*let DefaultIcon = L.icon({
    iconUrl: icon,
    //shadowUrl: iconShadow
});*/

//L.Marker.prototype.options.icon = DefaultIcon;

function Interval() {
    const [text, setText] = React.useState(0);
    var result = Fetch();
    useEffect(() => {
        //Implementing the setInterval method
        const interval = setInterval(() => {
            setText(result);
        }, 1000);
        //Clearing the interval
        return () => clearInterval(interval);
    },);


    var latcheck = parseFloat(text);
    //console.log(text)
    if (latcheck > 0) {
        //var posizione = text;
        //console.log(text);
        return (
            <Marker position={text} icon={GetIcon()}>
                <Popup>
                    A pretty CSS3 popup. <br /> Easily customizable.
                </Popup>
            </Marker>
        )
    }

};

export default Interval;

The solution stands in particular in this part of code:

function Interval() {
    const [text, setText] = React.useState(0);
    var result = Fetch();
    useEffect(() => {
        //Implementing the setInterval method
        const interval = setInterval(() => {
            setText(result);
        }, 1000);
        //Clearing the interval
        return () => clearInterval(interval);
    },);

and where the Fetch() component is this:

import textfile from "./data.env";
import React from "react";

function Fetch() {
    const [txlat, setText] = React.useState();
    const [txlon, setText2] = React.useState();
    fetch(textfile)
        .then((response) => response.text())
        .then((textContent) => {
            const pos = textContent.indexOf(',');
            //const pos2 = text.indexOf(pos);
            //const pos3 = text.indexOf(pos2);
            const lat = (textContent.substring(0, pos));
            const lon = (textContent.substring(pos + 1, textContent.length));
            setText(lat);
            setText2(lon);
        }, []);
    var resultlat = parseFloat(txlat);
    var resultlon = parseFloat(txlon);
    //console.log(geopos);
    //if (resultlat > 0 && resultlon > 0) {
        var geopos = [resultlat, resultlon]
        //console.log(geopos);
        return (geopos);
    //}

}

export default Fetch;