How to use Advanced Markers with React

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hi I'm Lee Halliday and today we're going to be building an app using the advanced marker functionality built into Google Maps this is the Opera building and it's built inside of react but what the advanced markers functionality allows you to do is to render markers like these three we have here but to do them with fully custom HTML so that we can attach events to them so here when I hover over here it expands out and applies some CSS classes so that we get these animations but we can also put the click event on it so that we can go and edit this content because we're doing this in react we can do this very easily so I'm now editing this sunny location over Orangeville and I can change it to cloudy and I can update its temperature you see it updating here in real time and then we'll close that out so this is the app we're going to be building and if we pop over to our local version of it you'll see that we don't have much yet so that's where we're going to get started if we go into the code we're working inside of next.js and I'll explain some of the code we already have here which I've pasted in to save us some time and me typing all of these characters out so we have Imports at the top and we'll talk about each one of them as we need them we have our app component which is the only thing rendering right now A div that says map and then we have some map options and weather data and we'll go over all of this as we need it so the first thing we need is to load the Google JavaScript the script itself and to do that we're going to use this wrapper component from Google Maps react wrapper so we can paste this in like that and we need to give it some some props for it to work so the first prop we need is the API key for our Google Google developer console account and I've got it in an environment variable here in dot ends dot local so we can go and copy this so we'll access it with process dot ends Dot and then we'll paste in the key now because the advanced marker functionality is brand new it's in beta right now I have to pass in version beta of the script otherwise we won't have access to this functionality and the last thing we need is to load the marker Library so we'll just pass an array of libraries and we'll put in marker so now inside of wrapper the children will be rendered when the script has loaded correctly so we're going to render out a my map component which doesn't exist so we'll go and create this right here my map and we'll just return a div for now that says map so I save it in my auto formatting fixes my code and we'll go back to the browser and we'll see that it still says map but we'll say script loaded like that come back here and you can see that it's only rendering it when the script is loaded and because we have the script now we should be able to create an instance of the map inside of here we're going to put that instance of the map into state so we'll say map and set map is equal to use state and when are we going to set the map in state we'll do that inside of a use effect hook so this use effect with zero dependencies is called once after the first render and in here we'll call set map and we'll pass it a new instance of window dot Google dot Maps dot map and then we need to pass in a few options well the first param we need to pass it a ref to the div that it will render the map onto so let's set that up right now and then we'll talk about the options we pass in so I am going to do a fragment here like that and inside of the fragment I am going to put a div and on the div we're going to put a ref so I don't have this ref yet but I'll come up here and I'll say ref is equal to use ref and a ref is basically a place you can put data it's a mutable place you can put data but that it doesn't Trigger or re-render in react um so it's not going to watch for changes to that value to re-render and update what the HTML looks like I'm also going to give it up give it an ID of map because I've got some CSS that will basically make it 100 width and 100 VH height to fill the whole screen so if I save this I now have the ref and I can put in here ref.current to access whatever value it has currently and now we pass in the map options so we already had this set up here so what I'm doing is I'm passing in the map ID which is also loaded from an environment variable and if we look here this is the map ID I'm using it's it's a gray version of a JavaScript Vector map so I have got this map ID in my code and we'll fix this in a second and I have to tell it where the center is so where to load the map what position and what zoom level to be at and in this case I've disabled the default UI as well so we'll come back here we'll hit save we'll reload the page and now we've got the map rendering over Toronto and it's using this gray map that I showed you over here in the Google Maps developer console so with this loading we can now come and basically start to render out the markers on the screen so what I'm going to do is I'm going to say when there's a map so we'll do map and and we will render the weather and I'm going to need access to this map instance so I'm going to pass it down as a prop to weather all right so I'm going to pop all the way down under this weather data because that's what we're going to be rendering out onto the screen as markers so we'll create a function called weather it is going to receive a prop of the map that's the instance of the Google Map and then what I'm going to do is start to render out this data the first thing I'm going to do is put this data into State why am I doing that because yes it's static at the beginning but eventually we're going to be editing this data and we want it to be re-rendering as it changes so for that we got to put it in state so we'll start and we'll say that we've got the weather and set weather like this and that will be equal to um actually why don't we call this data and set data just like that cool so we're going to be setting it to use State and the initial value will believe the weather data like that so now we want to render out by iterating all over all of the different weather data so there's three of them like this and we're going to be putting this inside of a fragment like this and because it's an object it's a little bit more difficult to iterate over so what we're going to do is use object dot entries so we'll pass in the data and then we can map over the result of that so what it gives us is an array where the first value is the key and the second value so that would be a b c and the second value is its value so this weather data right here just like that and we're going to be rendering out a marker for each one now this would fail if I loaded the screen so if we just save that and go back here because I haven't defined marker yet so we need to go and create that component but before we do that let's just start to pass the data down to it that we know we're going to need so what does a marker need it's going to need the map because we need to be adding markers to the map that we're rendering on the screen we also need a key anytime you iterate over anything in react you need to pass a key so we can just pass this key here so that it can keep tabs on on what markers it's rendered and when to re-render and things like that and I think that's it for now but we'll eventually need to pass more things into the marker but we'll add those as we go so we'll close out this marker and in here let's just put a div and the div is going to have an H2 and the H2 we will render out the weather dot climate so that would be the uh sunny cloudy or raining so if we save that we obviously haven't created the marker itself yet so we're still getting an error so why don't we come below and we'll create the marker so we're receiving the map we're receiving this HTML so the way that's passed down to this component here is children and we actually need the position of where to show this marker as well so let's pass the position down here weather.position and that will arrive down here as position perfect so even though we've passed this HTML down we're not going to render this in the normal way because we need to basically bridge the gap between jsx and react nodes in react but the advanced marker it wants to receive a Dom node or HTML so we have to go through this translation exercise where we basically go from what's happening in react and get that over into HTML and Dom land so in order to do that we are going to put it in a use effect and this first one is basically going to set up some things that will be eventually um reusing every time the children or the HTML that's passed to the marker changes so the first thing we need to do is we're going to set a ref to put our instance of the marker in and at this point I'm not talking about the um the marker component but I'm talking about the actual marker in Google Maps so we're going to say const marker ref is use ref and I'm also going to create another ref at the same time called the root ref and we'll talk about what that means in a little bit but it has to do with the translation of react and react Dom and nodes into HTML and um dominoes that that happen to be in HTML so there's that bridging exercise that we need to worry about so the first thing I'm going to do is I'm going to check if the root ref current if there's not a value in this ref that's when we when we need to initialize now you might be thinking well this is only going to run once anyways because you've passed no dependencies and that means it's only going to run the first time this component is mounted that's true in production but in development mode in strict mode in react 18 it happens to run this twice and I spent a lot of time with it messing with me as I was trying to do this and I found the easiest way to get around that is to just check and make sure that it's not already set a value so what we're going to do here is we're first going to create a div now we're not going to put the div on the screen we're just going to create it in memory and we're going to call it container so this container we need to say document.createelement and we want to create a div so we'll save that and then what do we do with this div container we're sort of going to create almost like a mini react app that we're going to render our react into so anytime the react re-renders it will go and update the HTML inside of this container so this is the bridging exercise of us sort of going from react and rendering it into a div which allows us to sort of bridge that gap between um Google Maps and sort of normal JavaScript world and react World and to do that we're going to use this root graph and we're going to set its current value to create root and what do you pass to create root you pass the uh the element the the Dom node this container in our case just like that so I am importing create root from react Dom client and that's where it comes from so I've set up basically a mini react app we haven't done anything with it yet we will look at sort of how to render things into that in a second but I'm going to set up the second thing I need which is an instance of an actual Advanced marker so we're going to say marker ref dot current and that is going to be equal to a new google.maps.marker DOT Advanced marker View and what we're going to pass into this at the beginning is its position although we are going to be updating this later on sort of because perhaps the position changes as the as the app is already running but the second thing we're going to pass is basically what to display in this marker so content and it's going to display whatever is being put inside of this div so container like that cool so if I come back here the map is rendering but we've got nothing showing up on the screen yet so we're going to fix that and the way we're going to fix that is adding a second use effect but this one is going to run more frequently this one is going to run anytime the map changes or the position changes or the children change so basically anytime there's an update to the map that's passed where to to render it on the map and the children this HTML here we want this use effect hook to run so that we can update our instance of the advanced marker view which we've put inside of this ref here so we'll come here and first we need to update the content in this container so the way you do that is you access the root ref erent value and you tell it to basically re-render and what do we want to re-render the children so this HTML here like that so react will render update whatever's in the container and because that's the content of our Advanced marker it will automatically be reflected so the next thing we're going to do is update the position of this just in case it changed so we're going to say marker ref.current.position is equal to position and I don't think this would happen but I think it's just a good idea to update the map as well just in case for whatever reason that changed maybe you had multiple maps on the screen at once or something like that so if we save this and come back it's hard to see but you can sort of see it raining there let me just fix that by coming up here and adding a class name of marker because I've got it styled to show up as black so now we have HTML rendering inside of an advanced marker View and we've done it through creating these mini react apps that when the children change they re-render into this div that we've created and that div is being shown in the advanced marker so that was a little bit of a mouthful and quite a bit of a translation exercise to basically bridge the gap from react to HTML and JavaScript but now that we've done that we can sort of just fully work up here in react land and it will feel like a normal react app even though what's being shown on the map isn't entirely react foreign so let me just first pull up the CSS and just show you that for an example um I've got a class of marker and it's got a background of map and some padding so I'm going to be referencing a few of these classes here and that's going to be why it displays the way it does so the next thing I want to do is fill out the rest of this content inside of this div so the first thing we're going to do is we are going to inside of here as a class put the climate so this here so we're going to say weather dot climate dot two lowercase and if we save that you'll see that I get this little icon that's showing up so in CSS I've basically added an emoji that looks for this class name of Sunny rainy or cloudy and that's why that's showing up the next thing we're going to do is we're going to come below the H2 and we'll just add a div like that and in the div we're going to put the temperature so weather.temp and we're talking about Celsius so we'll put a c come back you can see 20 degrees Celsius now you just because we're in xjs and it has hot module reloading you just save and it will automatically update the content on the screen so with that in place what I want to do now is when you hover this I want to add a highlight class so that it it does the animation that I've set up in in CSS already so I'm going to add some new state to keep track of what which of the markers I'm highlight I'm hovering my mouse over or highlighting so we're going to say highlight and set highlight and that is going to be use state just like that so what I'm going to do is I'm going to modify the class here to start with and we'll say if the Highlight is equal to the key so that would be a b or c if that's true we will add a class called highlight otherwise we'll just render out an empty string like that so I save it and it reformats it a little bit but we're just conditionally adding a highlight class so the next thing we're going to do is we're going to say on Mouse enter so when the mouse hovers over that we are going to call a function that sets the Highlight to the key and when the mouse leaves we're going to call a function that sets the Highlight back to null just like that so now when I hover state is updated state is removed it adds that CLA that uh a b or c to the highlight and that adds the Highlight class and I come out and it's removed and because I've been using animations in CSS it sort of does that animation that widens and you can see that I've got the Emoji fading out into the background like that so when I'm highlighting what I want to do is show the five-day forecast so I'm going to come down below here and when do I want to render the five-day forecast I want to render when the Highlight is equal to the key so when that is true I want to render out a div like that otherwise we'll just render no so in the div I'm going to give it a class name of the five they and now inside of here we're going to put a p that says next five and another P that takes this five day data here and basically joins it with a comma so we're just going to say weather dot five day and join with a comma like that so we come back we highlight again and it renders the five-day forecast and I have a CSS animation on that that basically fades it in so if you want to see what that looks like we'll go to globals we'll go down to five day and you can see that there's an animation called fade in and fade in goes from opacity zero all the way up to opacity one so that's how you get that effect of it fading in the five-day forecast and that's also how the Emoji Fades out it has an animation attached to it that fades it out from one opacity to zero opacity so because we're in react right now we're not really taking full advantage of it we're just sort of adding and removing a highlight class what I want to do is basically allow you to click this so we can attach a click event to the advanced marker and when that's done I want to open up a little panel here that will allow me to edit the content of that marker so we're going to close this and come back here and right on this marker itself I'm going to attach an on click event foreign click and what do I want to do on click I want to set um some state of which marker I'm editing so we don't have that yet so we'll just pop up here so what are we editing set editing and use State hook and I'm going to store the key in that as well so a b and c so we'll say set editing and we'll pass in the key like that just like that so it doesn't do anything yet but when I click it is storing in state the editing the key that we're editing so now I need to actually render out a component that allows for the editing so we'll put that up here and we'll say when editing we are going to render a component called editing that doesn't exist yet so why don't we go and create it we will go all the way down to the bottom function editing like this and we'll just return a div that says editing and we'll give it a class name of editing now there's one thing I forgot to do is to basically use the on click event um that we've attached to our marker so we're passing on click as a prop down to our component but we didn't receive that so we need to attach it here and then we need to take this function and attach it to our actual marker so what we're going to do is we're going to put that into a variable called a listener and we're going to say marker ref.current dot add listener and we're going to be attaching The Click event and what code do we want to run when you click the actual marker we want to call this function here on click now why did I put it into a variable now when I was editing this I was console.logging actually why don't we even demo that so we are console.logging why don't we put this like this and we'll console.log the key like that and I'll open up the developer tools clear that out so I was clicking and it was saying okay you clicked five times I didn't click five times I clicked one time I'll click this okay I click 10 times 13 like it wasn't making a ton of sense to me I was like why is it running that event 16 times and it's because as react was sort of re-rendering and doing its thing it was constantly reattaching new event listeners to the same marker so I had like 16 event listeners on the marker so to fix that what you need to do is return what's called a cleanup function so anytime in a use effect runs it runs the main function but if you return a function whenever that use effect is no longer valid so whenever the Second Use effect runs it first calls the cleanup of the first use effect so all we need to do is say listener remove so take this listener that was previously previously attached and remove it so that when you add a new one there's still only one instead of many so we'll just close this I did see an error let me let's see what that is okay that's probably a transient error just because we're working in in Dev mode sometimes that happens um so now when I look at developer tools it's just a b c it's only happening one time because it's always removing the previous listeners much better that little uh returning a cleanup function from here okay so we've attached The Click event and we're updating State I can remove this because we don't need that anymore like that and now we actually want to work on our editing component so what are we going to pass to our editing component we need a few things we need the weather data itself and we need to basically access the the data at the editing key so that will get us the weather of the um the place that we're editing right now that's the first thing we need to pass the second thing we need to pass is basically give the editing component a way to update this data so we're going to pass an update prop and it is going to receive a function and this function is going to receive the new weather so we're going to save this out and go in here because it's a little bit complicated so what we're going to do is we're going to take this weather and we want to update only the key that we're editing so we're going to call set data and if you pass a function here you get the existing data that's previously in there and you need to return whatever the new data should be so we'll take a copy of existing and then we want to change just the one that we're currently editing so you can do that with a dynamic key of editing and then what we're going to do is basically copy into that key the new weather like that the last thing we want to be able to do when we're editing is basically cancel the editing of that key so we'll pass a close prop and all it is going to do is set editing to null like that so we've done everything we need to here so why don't we go and fill out the editing component so we'll go down to the bottom and this editing it receives weather it receives update and it receives close so now we need to go and use those so the first thing we can do is we can put in H2 here and we can just say editing weather dot name and I didn't need these additional curly braces like that so we're editing Guelph so that would be this one over here if we click this we're editing Toronto and below the H2 we want to First allow the user to change what the climate is for that area so we're going to put a label and we're going to say html4 and that is going to be for one called climate and that's going to say climate right here and we're going to put a select on here so select what it's going to receive is the ID to match it up to the label and the second thing it's going to receive is what the current value is so that would be weather.climate and then what to do when it changes so on change we're going to receive an event and then we want to call um the update function and when we call the update function we're going to take a copy of the weather and then we're going to change the climate to be the event Target so the select itself dot value like that that's a bit of a mouthful but now let's put in the options into that select so we're going to just pass a hard-coded array that says sunny cloudy and rainy raining and we'll map over them so that will just be the vowel and for each vowel we want to render an option and the option will need a key because we're iterating so that can just be the vowel needs a value which is Val and the display is also valve so there's just sort of vowels everywhere save that we come back here and Toronto is raining but we can make it sunny and I when I'm editing this I want to also highlight it so I just need to go and tweak one thing if we go up here and we look at where it's adding the class we can say if it's if the Highlight is equal to key or the editing is equal to key highlight so now it's highlighting it's sunny we can change it to raining and because we're in react anytime we change the data it's re-rendering which causes us to render into that little div container and update the content of our Advanced marker so the last thing we're going to do is we're just going to allow the user to change the actual temperature so we'll just say label html4 temp we'll say temperature and then in here we put an input an ID of temp like that as well and this is going to be an input of type number its value is going to be weather.temp and then on change same sort of thing we did up here we are going to receive the event we're going to call update take a copy of weather and this time we're changing the temp with the E dot Target dot value like that so now we can up this down up and down and you can see that this is changing in real time and if we want to always show the five-day forecast we can just update this one with the same sort of logic or editing is equal to keep like that so now always show us the five-day forecast in there but if we want to be able to close this we just need to add a button so we can put that down here and we'll just add a button and the button will say close and inside here we'll say type button and on click what we want to do is call close like that so I call close it cancels out the state so we can go and we can click this one so we're editing Orangeville we'll change it to cloudy we'll modify the temperature close that we'll come over to Guelph we'll make Guelph sunny but it's a bit cooler so sunny and 15 degrees cool we'll close that so we've done a lot in react using the advanced marker functionality that now comes in Google maps and we saw how to sort of bridge the gap between react land and the document the HTML land and we did that specifically by creating a div putting it in a variable and then a little mini react app using the create root function where every time our children or in other words all of this content here is passed into marker and it changes we can re-render that content into our container and it will update the advanced marker View now there's more you can do with Advanced markers you can change what to do if there's a collision if there's sort of two markers in the same area you can set the Z index of them and whatever one has the higher that index will be the one that ends up showing and you can you can add all sorts of different you don't have to use HTML as their content you can use all different types of icons and change their background and their size and stuff like that but I thought this is a cool demo to show the mixing of react together with this new functionality hope you enjoyed the video take care [Music] foreign [Music]
Info
Channel: Google Maps Platform
Views: 19,871
Rating: undefined out of 5
Keywords: How to use advanced markers with React, getting started with using markers with react, how to use make a 5 day weather forecast app with react, how to make a weather app with React, HTML, divs, root functions, React, Advanced Markers, Google Maps Platform, Leigh Halliday, Geocasts
Id: 8kxYqoY2WwE
Channel Id: undefined
Length: 35min 19sec (2119 seconds)
Published: Thu Feb 02 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.