Home > Net >  A delete button in React component cannot get the useState from page
A delete button in React component cannot get the useState from page

Time:05-09

I am making a Google Map API app. But I have a trouble calling the setMarker(useState) from the component.

It said, Uncaught TypeError: Cannot read properties of undefined (reading 'filter').

I want to make a table to show my search location results and store to the useState(markers). It works, however, when I want to delete the location results by click the button, it's not work. What should I do to make a delete button. Thanks

My Map.js/App.js

import React, { useState, useEffect, useRef } from "react";
import {
  GoogleMap,
  useJsApiLoader,
  Marker,
  StandaloneSearchBox,
} from "@react-google-maps/api";

import Tablerecord from "../components/Tablerecord";

const libraries = ["places"];

const containerStyle = {
  width: "100%",
  height: "400px",
};

const inputStyle = {
  width: "100%",
  height: "500px",
};

const center = {
  lat: 22.7658314,
  lng: -22.4137297,
};

const options = {
  disableDefaultUI: true,
  zoomControl: true,
};

function App() {
  const [markers, setMarkers] = useState([]);
  const searchBox = useRef(null);

  const [searchPlaceCenter, setSearchPlaceCenter] = useState([
    parseFloat(43.7658314),
    parseFloat(-79.4137297),
  ]);

  const { isLoaded } = useJsApiLoader({
    id: "google-map-script",
    googleMapsApiKey: "API-KEY",
    libraries,
  });

  return isLoaded ? (
    <div>
      <StandaloneSearchBox
        onl oad={(ref) => (searchBox.current = ref)}
        onPlacesChanged={async (event) => {
          await // Find the search field value and make it be center value.
          setSearchPlaceCenter([
            parseFloat(
              searchBox.current.getPlaces()[0].geometry.location.lat()
            ),
            parseFloat(
              searchBox.current.getPlaces()[0].geometry.location.lng()
            ),
          ]);
          //  Store Search geolocation value to useState markers for Red markers
          setMarkers((current) => [
            ...current,
            {
              lat: searchBox.current.getPlaces()[0].geometry.location.lat(),
              lng: searchBox.current.getPlaces()[0].geometry.location.lng(),
              name: searchBox.current.getPlaces()[0].formatted_address,
              time: new Date(),
            },
          ]);
        }}
      >
        <input
          type="text"
          name="address"
          placeholder="Search Address"
          autoComplete="off"
          style={{
            boxSizing: `border-box`,
          }}
        ></input>
      </StandaloneSearchBox>

      <GoogleMap
        mapContainerStyle={containerStyle}
        zoom={8}
        //  Set center to searchPlace location to change center
        center={{
          lat: parseFloat(searchPlaceCenter[0]),
          lng: parseFloat(searchPlaceCenter[1]),
        }}
        options={options}
      >
        {markers.map((marker) => (
          <Marker
            key={marker.time.toISOString()}
            position={{
              lat: parseFloat(marker.lat),
              lng: parseFloat(marker.lng),
            }}
          />
        ))}
      </GoogleMap>

      {/* !!!!!!!!Here is my question !!!!!!*/}
      {markers.map((marker) => (
        <div>
          <Tablerecord key={marker.time} marker={marker} />
        </div>
      ))}
    </div>
  ) : (
    <div>Loading...</div>
  );
}

export default React.memo(App);

My Tablerecord.js(component)

import React, { useState } from "react";
import styles from "../styles/tablerecord.module.css";

const Tablerecord = (marker,{markers,setMarkers}) => {


  const handleRemoveLocation = (e) => {
    const name = e.target.getAttribute("name");
    console.log(markers) // undefined
    setMarkers(markers.filter((item) => item.name !== name));
  };

  return (
    <div className={styles.table}>
      <center>
          {/* This work, can show name,lat and lng */}
        <p name={marker.marker.name}>Name: {marker.marker.name}</p>
        <p>
          lat: {marker.marker.lat}, lng: {marker.marker.lng}, Added Time:{" "}
          {marker.marker.time.toTimeString()}
        </p>

        {/* Delete button I want to ask */}
        <button name={marker.name} onClick={handleRemoveLocation}>
          x
        </button>
      </center>
    </div>
  );
};

export default Tablerecord;

CodePudding user response:

You're close, but not quite sending through the right props to the table record component.

<Tablerecord key={marker.time} marker={marker} markers={markers} setMarkers={setMarkers} />

Then,

const Tablerecord = (props) => {
   const { marker, markers, setMarkers } = props; 
   // ...
}

or if you prefer:

const Tablerecord = ({ marker, markers, setMarkers }) => {
   // ...
}

CodePudding user response:

I believe you need to add the states into the component, lmk if this works

<Tablerecord key={marker.time} marker={marker} markers={markers} setMarkers={setMarkers} />

CodePudding user response:

Thank you for all the above comments!

At last, I adjust the code of the "Tablerecord" component and few of "Map.js".

Here is my code

Tablerecord.js(component)

import React, { useState } from "react";
import styles from "../styles/tablerecord.module.css";

const Tablerecord = ({ marker, markers, setMarkers }) => {
  const handleRemoveLocation = (e) => {
    const name = e.target.getAttribute("name");
    //   markers will output an Object to use .filter
    // filter out the item which is equal to the name.
    setMarkers(markers.filter((item) => item.name !== name));
  };

  return (
    <div className={styles.table}>
      <center>
        {/* String type - name , lat, lng and time */}
        <p>Name: {marker.name}</p>
        <p>
          lat: {marker.lat}, lng: {marker.lng}, Added Time:{" "}
          {marker.time.toTimeString()}
        </p>
        {/* marker.name can let setMarkers detect the name */}
        <button name={marker.name} onClick={handleRemoveLocation}>
          x
        </button>
      </center>
    </div>
  );
};

export default Tablerecord;

Map.js

<Tablerecord key={marker.time} marker={marker} markers={markers} setMarkers={setMarkers} />
  • Related