react google maps - Move data between functions - reactjs

I have the example code of react-google-maps and it works great.
I'm now trying to create a page where the user can influence what is displayed on the map (some kind of filtering).
I have 2 functions that need to talk to each other, the code built this way:
import {
withGoogleMap,
withScriptjs,
GoogleMap,
Marker,
InfoWindow
} from "react-google-maps"
function Map() {
useEffect(() => {
// Getting the data
}
return (
<GoogleMap
zoom={userLocation.zoom}
center={{ lat: userLocation.lat, lng: userLocation.lng }}
>
</GoogleMap>
)
Now that's where things get a little complicated:
const MapWrapped = withScriptjs(withGoogleMap(Map))
export default function App() {
return (
// user interface for filtering goes here!
<MapWrapped
googleMapURL={`https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=${''}`}
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `100%` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
</div>
)
}
I need to get data (useState) from the function Map to function App.
I can't find a way to do so.
I can't declare use state outside a function and if I put everything in one function the map just keeps reloading.

Just needed a good night sleep:
Changed the map function to look like that:
const Map = ((props) => {
And now I'm able to get props from the App function.
Will declare the useStates on the App function and move the data that way

Related

Next js with react-leaflet window is not defined when refreshing page

im using react-leaflet in Next js but when reloading page shows "window is not defined" even i am using dynamic import with ssr:false,
i saw this question made by others here and tried answers that they offered but didn't work, also tried to make the map mounted after component but again no result,
my code:
function ContactPage() {
const MapWithNoSSR = dynamic(() => import('../Map/Map'), {
ssr: false,
})
return (
<div className={styles.map}>
<MapWithNoSSR/>
</div>
)
}
function Map(){
const [markers, setMarkers]= useState([
{cord:[12.3774729,20.446257]},
{cord:[45.3774729,10.45224757]},
{cord:[40.3774729,15.4364757]},
])
<MapContainer center={[12.374729,22.4464757]} zoom={13} scrollWheelZoom={true} style={{height: "100%", width: "100%",zIndex:'1'}}>
<TileLayer
url={`example.com`}
attribution='Map data © <a>Mapbox</a>'
/>
{markers?.map((element,idx)=>{
return <Marker
position={element?.cord}
draggable={true}
animate={true}
key={idx}
>
<Popup>
Test PopUP
</Popup>
</Marker>
})}
</MapContainer>
}}
}
as you were told in the comment, dynamic () has to go outside of the component or screen you are going to return, e. g.
import dynamic from "next/dynamic"
const MyAwesomeMap = dynamic(() => import("../components/Map/index"), { ssr:false })
export default function inicio() {
return(
<>
<p>Example Map</p>
<MyAwesomeMap />
</>
)
}
Your Map component doesn't return anything

Resize google map frame in react js

Currently using google-maps-react component in a contact form for a sales page. This code has successfully imported the map and it is viewable in the dimensions 450x350. My issue is, is that despite the image being 450x350 the frame or i guess div that the map api sits in still thinks the map is still default size so it pushes my entire site out with white space that is removed when i remove the Map API. No amount of adding styles as dimensions to anything around the map has fixed this.
What do i pass into the map in order to effect the size of the frame and not just the image itself?
import React, { Fragment } from "react";
import ContactForm from "../contactus/ContactForm";
import { Map, Marker, GoogleApiWrapper } from "google-maps-react";
const ContactUs = props => {
const style = {
maxWidth: "450px",
height: "350px",
overflowX: "hidden",
overflowY: "hidden"
};
return (
<Fragment>
<h2 className='lead text-primary text-center'>Get in touch</h2>
<div className='grid-2'>
<div>
<h4>Priority Consulting</h4>
<ul>
<li>
1234 Sherman Way <br />
Sherman Oaks, CA 90210
</li>
<li>info#priorityconsulting.com</li>
<li>1-800-324-3423</li>
</ul>
<Map google={props.google} style={style} />
</div>
<div>
{" "}
<ContactForm />
</div>
</div>
</Fragment>
);
};
export default GoogleApiWrapper({
apiKey: "MYKEY"
})(ContactUs);
I went back into my code and found an updated version, that made it to a final version of the site. Unfortunately the site is no longer live so cant verify if this is the best answer but, like I said its in my code, so it probably solves.
const style = {
maxWidth: "450px",
height: "350px",
overflowX: "hidden",
overflowY: "hidden"
};
const containerStyle = {
maxWidth: "450px",
height: "350px"
};
<Map google={props.google} style={style} containerStyle={containerStyle} />

react-google-maps map not updated when passed props and the marker is one location behind when updated

I have the map working when it loads, but whenever I pass props the map itself never changes.
The marker changes, but is always 1 state behind what it should be, obviously a sync issue but I'm not sure how to fix this in my component.
class Map extends React.Component {
state = {
center: { lat: 50.937531, lng: 6.960278600000038 }
}
componentWillReceiveProps = () => {
this.setState({
center: {
lat: Number(parseFloat(this.props.city.lat)),
lng: Number(parseFloat(this.props.city.lng))
}
});
}
render() {
console.log(this.state.center)
return (
<div>
<MapDetails
googleMapURL="https://maps.googleapis.com/maps/api/js?key=AIzaSyB-L-IikkM6BZ_3Z2QIzbkx4pdAkP76tok&v=3.exp&libraries=geometry,drawing,places"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `100vh`}} />}
mapElement={<div style={{ height: `100%` }} />}
mapCenter={this.state.center}
/>
</div>
)
}
}
const mapStateToProps = (state) => {
return { city: state.CityNameReducer }
}
export default connect(mapStateToProps)(Map);
const MapDetails = withScriptjs(withGoogleMap(props =>
<GoogleMap
defaultZoom={12}
defaultCenter={props.mapCenter}
>
<Marker
position={props.mapCenter}
/>
</GoogleMap>
));
The biggest question I have is why the map itself is not updating?
Add a key to GoogleMap component. a Key should be unique each time provided. for your testing use new Date().getTime() function.
<GoogleMap key={new Date().getTime()}/>
as I mentioned its for only testing so make sure to provide this key in better way
I may recommend you to use shouldComponentUpdate(nextProps, nextState) {} instead of componentWillReceiveProps().
I recommend you to read the following page, to understand how it works.
Updating and componentWillReceiveProps
I don't have more information about what is happening in the parent of your component, so I cannot go deeper to the problem. But I think you can get the solution by changing that.

react-google-maps pass props on marker click

I am trying to integrate "react-google-maps" in my app to display a map. I am having the hardest time understanding their system for markers.
https://tomchentw.github.io/react-google-maps/#marker
I am able to display my map and get all of my markers displaying correctly. The next step is where I am having problems. I need to be able to click on each marker and know know what marker is being clicked on. I have commented the following code to show what props I am trying to show in my console for now. I think that I just need to pass another argument in the event but I have no idea how to do that. Truthfully right now I believe I am passing the event listener but I not even fully sure what I am looking at when I log that 'e' variable.
You can see what I have so far in my github. If you click on the marker you will see what I am logging.
https://joweber123.github.io/take-me-there/login/James
Please help, I can't find this information discussed anywhere else. Thank you so so so much
import React, { Component } from 'react';
import { withGoogleMap, GoogleMap, Marker, } from "react-google-maps";
import { compose, withProps } from "recompose";
class List extends Component {
//I eventually will use this information to set state and all of that, but for now I just don't understand how to pass information to this function from my marker on onClick
handleMarkerClick(e){
console.log(e);
}
render(){
const { compose, lifecycle} = require("recompose");
const {
withGoogleMap,
GoogleMap,
Marker,
} = require("react-google-maps");
const MapWithAMarker = compose(
withGoogleMap
)(props =>
<GoogleMap
defaultZoom={8}
defaultCenter={{ lat: Number(`${this.props.locations[Object.keys(this.props.locations)[Object.keys(this.props.locations).length-1]].location.lat}`), lng: Number(`${this.props.locations[Object.keys(this.props.locations)[Object.keys(this.props.locations).length-1]].location.lng}`) }}
locations={this.props.locations}
>
{
Object
.keys(this.props.locations)
.map(key =>
<Marker
key={key}
position={{ lat: Number(`${this.props.locations[key].location.lat}`), lng: Number(`${this.props.locations[key].location.lng}`) }}
locations={this.props.locations[key]}
//I want to be able to pass the information that is stored in my locations prop here, but I have no idea how to do that.
onClick={props.onMarkerClick}
/>
)
}
</GoogleMap>
);
return (
<div className = "location-list one-third column center border-main full-height">
<MapWithAMarker
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `400px` }} />}
mapElement={<div style={{ height: `100%` }} />}
locations={this.props.locations}
//I am not even really sure what I am doing here. What gets printed out in my console gives me some information but what I really want to be able to do is to pass the locations props of my specific marker and have access to that information
onMarkerClick={(e)=>this.handleMarkerClick(e)}
/>
</div>
);
}
}
export default List;
I was able to figure it out! I was just passing the event listener before so of course it didn't contain any of the information that I needed. I also didn't need to pass it its parent as just having it trigger its own event was enough. Thanks everyone for having a look at this.
onClick={()=> this.props.handleMarkerClick(this.props.locations[key])}
I guess I wasn't asking myself the right question but once I found these two answers I understood much better what I needed to do.
React - Passing props to child onClick
Pass props to parent component in React.js
Can you show what is contained in this.props.locations? Usually you want to map the locations and each location should have some kind of id field. Instead of mapping through the keys you should map through the array of locations. That way you can pass the id (or even the coordinates if they are in the location object itself, which I presume they do) when the onClick function is called.

MobX React: How to only Re-render part of View

I have a map react component and I'm dynamically adding markers.The problem is that when I add markers in the store, the whole map rerenders instead of just appending the markers to the map. Has anyone got any suggestions on how this could be fixed?? I'm pretty sure that I need to Inject the store into CPMap function exclusively, I'm just not sure how.
const CPMap = withGoogleMap((props) => (
<GoogleMap
ref={props.onMapLoad}
style={{
height: 100,
width: 100,
}}
onCenterChanged={props.boundsChanged}
defaultOptions={{ styles: this.mapStyles }}
defaultZoom={props.zoom}
defaultCenter={{ lat: props.center.lat, lng: props.center.lng }}>
<MarkerClusterer
gridSize={40}>
{
props.markers.map(({ key, position }) => (
<Marker
key={key}
position={{ lat: position.lat, lng: position.lng }}
icon={{
url: require('../../images/marker.png')
}}
/>
))
}
</MarkerClusterer>
</GoogleMap >
))
return (
<CPMap
style={{
height: 100,
width: 100,
}}
onMapLoad={(gMap) => {
map = gMap
this.props.map.fetchMarkers()
}}
boundsChanged={() => {
this.props.map.fetchMarkers()
}}
center={this.props.map.center}
zoom={this.props.map.zoom}
markers={mobx.toJS(this.props.map.markers)}
containerElement={
<div style={{ height: 'calc(100vh - 70px)' }
} />
}
mapElement={
<div style={{ height: 'calc(100vh - 70px)' }} />
} />
)
}
I'd propose you the following solution: don't pass makers directly to CMap component, but use store instead;
const markersStore = observable({
markers: []
});
Then in your component - move MarkersClusterer to the separate component and pass markersStore one level deeper:
//import markersStore or inject via mobx-react package
class MyComponent extends Component {
render() {
const CMap = withGoogleMap((props) => (
<GoogleMap
...
<Clusterer markersStore={props.markersStore} />
/>
))
return (
<CMap
...
markersStore={markersStore}
/>
)
}
}
Make your new Cluster component observable so it updates when markersStore "markers" property updates;
#observable
class Clusterer extends Component {
render(){
const { markers } = this.props.markersStore;
return (
<MarkerClusterer>
{ markers.map(...)}
</MarkerClusterer>
)
}
}
The final change is to update your fetchMarkers method so it populates the markersStore with new data.
With this solution CMap component doesn't know anything about markers and it doesn't updates when new data received. At the same time MarkersClusterer component becomes more clever and "observes" changes in the markersStore.

Resources