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} />