Adding A Map View And Search Results
Building A Real Estate Search App w/ GRANDstack: Part 6
We add a JavaScript map component using Mapbox GL JS and start showing some search results in our app using GraphQL & Apollo Client React hooks.
Links And Resources#
- Hi, folks. Welcome to the Neo4j Twitch stream. My name's Will, and today we are going to pick up working with our GRANDstack real estate search app. We'll pick up where we left off last time focused on the front end. So the goal for today is to add a JavaScript map component so we can start to search for properties, see some results on the map, and then start to view details about those properties. See if we can get that done today. So let's just go ahead and jump in. So leaving off from last time, let's just, let's make sure first we have, yup, got our database running. So last time we were working with Aura, so we can either connect to our Aura instance or have it locally, as well. Let's just give it a npm run start. And check localhost 3000. So while that's building, let me just drop in the link to the GitHub repo, if this is your first time checking the stream out. Drop that in the chat. So we've been working on this GRANDstack application forked from the GRANDstack starter project to search for real estate listings. We've been spending some time building out our database. We've done a little bit on the front end. Here we go, here's what we have in the front end so far. So this is where we left off last time where we updated the sort of dashboard view so we're seeing a few things like some summary statistics about the real estate market for the data that we've pulled in and some specific listings. What we wanna do today is, let's take a look, I'll open a new window here. Let's take a look at kind of the functionality that we're looking for in our applications. So if I open up Zillow, and let's search for a house for sale in San Mateo. And this is the kind of view that I have, right? I have this sort of split screen view where I, on the left, I have a map that I can move around and I find new search results as I move the map, and then on the right, I have more detailed information. When I click on one of these markers on the map, I can view some detailed information about the property. And then in this main view, this is also where I'm able to configure some of my search results. So maybe I want to set a maximum price on my search results, I can set a minimum number of bedrooms and bathrooms. That clears out my options pretty quickly in San Mateo. Anyway, so that's the basic view and functionality that we're looking for here instead of this sort of summary, dashboard view. Cool, so what we'll do, so we have this slide-out here, so we can see that we can select the users route, which takes us to slash users. And then the idea here in the GRANDstack starter, the idea was I could search for users by name, but I don't have users, so this is not a useful component. So instead, what we'll do, let's switch users here to our search and start to add some of that search in map functionality. So let's jump into the code. And here under web-react, we'll start with app.js. And we can see right away, this is in our sidebar view in the dashboard linking to slash users. Let's change this link to slash search. I'm gonna change this to search instead of users. And then here in our router switch when the path is slash search, since we don't have users anymore. We need to load a component. Let's call it search. Oops. Search. But of course, this is an error, because I don't actually have a search component. Let's try to import that one as if we did. Import search from components search. And now let's create that search component. So in the components directory, let's create a new file called search.js. And here import React, and then this will be initially just a simple functional component. Let's export default function search. And what is this search component going to do? Well, if we think back to how we were structuring the search functionality, we had a map view on the left. On the right, we had sort of a results detailed view. Up at the top, we had the toolbar for sort of selecting more specific search functionality if I wanna limit the price range or if I want to limit the number of bedrooms, bathrooms, that kind of thing. So this component, the search component, is what's gonna be responsible for a couple of things. One, it's going to be the component that's actually responsible for doing the data fetching. So it's going to know what sort of filters you've put on the search, what sort of area in the map you're looking at now so you know where to sort of narrow the search results down to. And then when it does that data fetching, so it's gonna go out to our GraphQL API, fetch the search results, and then what's going to do is render our map and result components. So think of this as, the search component as being responsible for allowing us to configure what we wanna search for and then handling the data fetching code. So initially, before we add any data fetching, it's just going to itself... Let's just put in a real simple search results here placeholder. Okay. Oh, did we actually add that Bluetooth searching outline? Did we add that somewhere? Oh, we did. I don't need to actually import that. That was just an autocomplete mistake. Okay, so now let's see what we have. Now if we go to search, we should see, yep, search results. Okay, great. So instead of just rendering search results, what we want this component to do is pass data to another component that's going to have our map view on the left and on the right our detailed results. So let's create another component in the components directory, and let's call this one maybe MapResults. And in map results, I want to do a couple of things. I want to render my map view, and then I also wanna render some detailed property list. So let's import React. And this will also be a functional component, so export default function map results. And what is it going to return? Well, let's turn to React fragments. And then in here, we'll have both our map component and some sort of detailed listing view. And if you think of how we wanna kind of lay that out, I mean, I guess we want some sort of responsive behavior. So if we go back to our dashboard, here we have some responsive behavior that if we're in a constrained or mobile view, we sort of give each of these components their own row. So we're using the grid layout functionality here. Let's take a look at how our dashboard component handles that. So here's our dashboard component, and we can see that it's using this grid layout from Material UI. So we create a grid container. We set some spacing. It's gonna be the spacing between the individual nested components in here, the grid items. Then for each grid item, we define the number of rows. This is based on a, or number of columns, rather. This is based on a 12-column layout where each row has 12-column width. So in this case, our ratings chart gets seven columns and our user count gets five columns when we're in full width, right? So here's seven. It's a little more than half. There's five for our, in this case, it's called user count, but it's really our property count. Okay, so we want something kind of like that. You can see we're also pulling in some additional styles. Cool, so let's jump back to our map results, and what we return now within our React fragment is going to be a grid container set, add some spacing on that. Let's go ahead and import grid here. Grid from Material UI core. Close the search there. Okay, so here's our grid. Then we're going to have an item. And so this is going to be the container holding our map view. And let's say when this is extra small, so when it's narrow width, it has 12 columns. That means it'll be in its own row. When it's medium, let's give it eight. And large, let's give it seven. So just a little bit over half. And let's say this is the map view. Cool. And then the next grid item, when it is extra small, it also gets its own row. When it is medium, we'll give it, eight minus 12 is four columns. And large gets five. And just a placeholder. This is going to be our detail view. Okay, let's run that. And go back to search here. And we need to replace our search results with our map results. So we'll import map results from map results and render that component here. Here we go, get the closing tag. Okay, and let's go to search. Cool, we see a map view and we see a detail view. Well, if you look in our dashboard, it has this nice kind of white background and some spacing. Whereas the search, we just kind of have the text over the background. This is the paper component in Material UI, which gives us this nice sort of background. Folks are saying little choppy audio, sounds like? Let's take a look. Other folks say it's okay. Yeah, hopefully the recording ends up okay. I'm not sure what's going on there. Everything looks normal from what I can see. So I'm sorry about that. Okay, so if we take a look in map results, what we want, let's add on with grid, add this paper component. And then what we wanna do is add the paper component as kind of a wrapper here, so paper around our map view and paper around our detail view. And, okay, that's kind of okay. But we can also add, I think, maybe some better styles here. Maybe this height could be a bit higher. So we haven't really talked about how we handle working with styles in Material UI. Material UI styles. So Material UI uses what's called the styled components API, or, you know, this is a version of CSS in JS. So basically, the way this works is we define some CSS rules in JavaScript here, in the sort of JSON format, and then we call the use styles hook, and then that gives us these classes that we can then add to our components. So class name, this is kind of JSX syntax for add classes to this component when you render it in HTML. And then we'll bring along all of these styles. We can also add themes. Does it talk about the themes here? So theming allows us to define sort of global styles that then can get brought along to our different styled components. So we don't have to define everything individually on each component for the styles. We can define them in the theme and then bring those along as we define our styles within the sort of styled components API. Cool, so let's take a look at how we do that. So the first thing we need to do, I'm gonna go ahead and set this up to pull in a theme, which we haven't really added yet, but we'll do that later on. So we'll just sort of get the default theme. Material UI core styles, I think, is where we can get use theme and then also makes styles. Okay, and then we'll say use styles equals make styles. And here's where we're gonna pass in our theme and then start defining some styles initially. Let's just go with this fixed height. We'll give that a height of, let's say 540. Fixed height, height 540. Okay, and what do we want? So where does the theme come from? Well, that theme is a hook. So at the very beginning, we'll say theme equals use theme. Okay, and I have some other styles here that I am just going to copy and paste in so you don't have to watch me type all of these. So we'll also define some styles for paper class. Okay, so anything with the paper class on it will have these styles applied to them. So some padding, some overflow, and then we also have this fixed height so that each one of... We can't see it now 'cause we have some errors. Each one of our individual components will have sort of a fixed height. So we always want our map to be at least 540 pixels. Okay, and then we can get our class names by calling our use styles hook, passing in the theme that comes from the hook. We get the class names that we can use. This clsx, let's go ahead and import that. This allows us to combine multiple of these class names. So we want both fixed height and paper, and this clsx allows us to do that. So now we can say on our, on this case, our paper component here, we wanna add class name equals fixed height paper for that one and for this one. Okay, let's see how we go. Cool. So now we have this nice white background. We have some padding. We have some spacing between these. We have some responsive behavior. As we shrink things, they each get their own row. Okay, cool. So now I think we're ready to add a map. So what we wanna do is have an interactive map in this container right here. There's lots of options for adding maps to JavaScript apps. We could do something like Google Maps, Apple Maps. There's an open source library called Leaflet. I like to use a library from Mapbox called Mapbox GL JS. Has anyone used this library before? So the nice thing about Mapbox GL is we can add lots of different custom styling to it through Mapbox. We can use Mapbox to handle our tile serving. It has an API that's pretty similar to Leaflet, if you've used Leaflet before. I think Mapbox also contributes a lot back to open source. I think they actually now sponsor the Leaflet project, maybe, something like that. So Mapbox GL JS is a JavaScript library that manipulates the DOM itself. And Mapbox itself doesn't provide a React wrapper for Mapbox GL JS, but there are some libraries out there that do. So if you just Google Mapbox GL JS React, you'll find, I think this first one is sort of an example showing how you can just create a React component that wraps Mapbox GL JS itself, and then there's some more opinionated ones like React Mapbox GL, which I think gives you some React components. So you're not sort of working with the core library itself. You're working with a React API that wraps it. I did something like that a while ago for this project, spacetime-reviews. Here's, let's see if this is still running. I'm not sure what database instance this is hitting, but let's see if this works. Oh yeah, still works. Cool, so this is hitting a Neo4j database that is loaded with data from Yelp. So Yelp releases a public data set. And what we're doing here is just trying to show off some of the Neo4j cipher functionality for doing distance searches. So here we're searching for businesses that have reviews within some time range. I assume you should be able to change this time range. Let's change this to just January. I don't know if that actually changed our search results or not. Anyway, if we look at the code for this, this is using Mapbox GL JS, which I just sort of wrapped in a map component. I'll drop the link to this in the chat, as well. Nice, Michael says new computer is on its way. Yes, it is. Hopefully I'm due for an upgrade. So what's going on? Let's make this a bit bigger. So here we've created a map component that takes in as props latitude, longitude, and how far it should be zoomed in. And then we have some helper functions for, in this case, this is for drawing GeoJSON, in that case, a circle. So this is how we're drawing this radius indicator. Then we have some logic for setting the markers. But the core piece here is in this component did mount lifecycle method. We're getting the container, so basically what element do we wanna populate the map in. And then here inside the component did mount function, we're actually calling the Mapbox GL JS library API directly. Then outside, so once we've built this component, then for example, if we take a look at, what do we actually call this from? Probably just from App.js is where we actually use map. Let's see. Yeah, so here, so we're doing our data fetching. In this case, we're using the Neo4j JavaScript driver to run some cipher queries. So kind of similar to the setup we want to have for our real estate search app where we have some toolbar here that has some configuration for some of the filters that we're going to do. Except rather than send a cipher query directly to the database, we're gonna end up sending a GraphQL query to our API. But yeah, but then once we've fetched the data, then we're basically just calling this map component from App.js. So anyway, so we could follow this approach where we just sort of wrap the Mapbox GL JS library within a React component, but I wanted to try a different library that I saw, which is this one. So there's a group called Urbica, which I think is based in Russia, that has built this wrapper around Mapbox GL JS. There's also an Uber version that Uber uses as part of their data visualization suite called react-map-gl. I had looked at this one when I was starting the spacetime-reviews, this demo, and I can't remember exactly, there was some functionality, though, that wasn't exposed here. So I guess that that's one thing to consider as we're choosing what map library to use and whether or not to use a React wrapper around these libraries. An important thing to think about is is all of the functionality that we're interested in exposed through the React wrapper around it? So, something to think about. Anyway, so this Urbica React Mapbox GL JS. So this version, they say, is heavily inspired by the Uber one. It looks like it has a bit more documentation and a few more components that it exposes. So you if we think of the basic functionality that we need for our map, well, we need to sort of display the map, we need to be able to add markers and pop-ups to it, and then we need to be able to draw. I think this is kind of one of the more important pieces of functionality that I think this was maybe not exposed through the Uber version of this, but I may be wrong. But basically, where we're allowing the user to draw some arbitrary polygon on the map and then do a search, in our case, within that polygon. So just looking over these components, it looks like everything that we need is exposed. So if we take a look at the docs here for react-map-gl, let's jump to their full docs. (hums) There we go, documentation website. Cool, so, installation, npm install dash save. So let's stop our React app. Go into cd web-react and install react-map-gl. And then the next step, we want to... (hums) Create a map. So we import Mapbox GL, import the CSS. Let's go ahead and add that while this is still installing. And then here's the basic call to Mapbox GL. So we'll replace this instead of our map view placeholder, we'll drop this in. Okay, so we're setting width and height. We have a CSS rule that we defined above where we set the height to be fixed at 540. So we'll just set the height to be 100%. It's using a specific Mapbox style. So one thing I really like about Mapbox is it has a bunch of different styles that we can use and pull in. So we'll just keep the default for now. Latitude and longitude for the initial center of the map. And then it has this Mapbox access token. So we do need to get a Mapbox access token. Fortunately, these are free. Mapbox I think at some points based on the usage determined by the number of tiles that you're serving, I think Mapbox will charge, but we don't need to worry about that initially for this application. So I've already signed in here. Let's see how we can create a new token. Access token, create a token. We're gonna call that, let's call it willow-grandstack. And I just need the public, all this is gonna do is just be used to pull down vector tiles. I'm not gonna use any of the custom things to pull things into, to tie it to my account or anything like that. It says the token will work from requests originating from any URL. Yep, that's what I want. And my password. Okay, and here's my token. So we'll copy that, and we could just paste it in here, but what I wanna do is set this as an environment variable 'cause I don't want to necessarily check this into GitHub. So we're using Create React App, which has a great convenient feature that any environment variables we declare that are prepended with react underscore app underscore at build time kind of get replaced in the HTML. So you may wonder what does environment variable mean in the context of a client app, and that's really all it's doing. It's just sort of some magic where it's taking values defined as environment variables and then actually writing them in HTML. So this is not super secret. This is gonna end up being exposed in the client's application anyway. But it sort of simplifies our build process. So let's go ahead, let's call this React app Mapbox token. Close that, and then in my map, here we can say process.env.MAPBOX_TOKEN. Okay, so we've installed our map. Let's go up a directory and npm run start. And while that's building, let's take a look at the docs here. So what should we expect? So we should, I think, expect to see exactly this. Just a basic static map centered at San Francisco. Our GraphQL server's running. Looks like our React app is still building. Okay, so once this is running, we'll need to switch it to use this inter active mode. You can see here where we're just using a use state hook to keep track of the latitude and longitude and how zoomed in we are. And then the next thing we wanna do is actually pull in some search results. So we want to query our GraphQL API, and then we want to actually add some markers on the map that are indicating where the property results are. And then we want something to happen when we click on those that we end up viewing the details for that. Okay, so we're still building. We're almost done. API access token is required to use Mapbox GL. Process.env.MAPBOX_TOKEN. And what did we call it? Mapbox token. (hums) And why didn't that get set for our map? (hums) Maybe I'm not actually, we don't initialize that correctly somehow? Well, let's just copy/paste that in here for now. Figure that out later. Just wanna make sure this is working. Okay, there we go. That is a static map. Oh, I know what I did wrong. It's not process.env.MAPBOX_TOKEN. It's REACT_APP_MAPBOX_TOKEN. This value. There we go. Yes, Michael says, React app. Thank you. Cool, so, okay, this is static. That's not what we want. The next step in the docs here says how do we change this to interactive map? So if you look at what's going on here, so React with functional components, we have this use state hook that we're using to update the state in a component that triggers a rerender when that state changes. And in this case, we're keeping track of this in, for us, what is our map results component. So let's just add that here. We'll need to import use state from React. And then latitude, longitude, and zoom are now being bound to viewport.latitude and viewport.longitude, which is here defined in our use state hook. So instead of setting those directly, we'll bind those to the viewport state value. And we need to add this on viewport change handler to call set viewport state. So set viewport is this function. So the second value that we get back from the use state hook, the first one is the variable that holds the state value, and the second one is the function to update that state value. So we pass in that function, set viewport for the change handler, and the viewport in our map changes so that it updates the state of our component. Cool, so instead of centering this on San Francisco, let's center it for the area for the data that we have. So let's grab, actually, we have that somewhere, don't we, in GitHub? Willow-grandstack. Take a look at data. Here's the point we were using. This is where Montana State University is, but that's a good sort of point to use to start off. Okay, so latitude is that. Longitude is this value. Great, we're centered on Bozeman. Zoom level, this is gonna zoom us in a lot more. So will this be, oh yeah, it's probably too much. Let's say 15. That's sort of like a neighborhood level is kind of where we want to be zoomed in at. Yeah, that seems like a good spot to be zoomed in at. Kind of right over the University of Montana campus. Cool. Okay, so now we need to fetch some data to actually put on our map. So let's take a look in our GraphQL API, so localhost:4001/graphql. Oh, that's from a previous project. By the way, since that was already loaded, here's a similar project. I got kind of obsessed with this idea of, they're called geoglyphs. So it's basically geoglyphs are any sort of manmade marker that indicates some geographical area. And in a particular area in the United States, it's it's common to have these large- Oh, that's too big. To have these large, like, hillside markers. So you'll see big letters on the top of hills throughout this sort of area. And there's a Wikipedia page devoted to these things. So here's an image for a C on an hill by University of California Berkeley. But I thought it was cool that Wikipedia had the location and some information on each one of these, so I wrote a little scraper to pull this into Neo4j and then built this kind of simple app to visualize some of these, which is kinda similar to what we're doing today. This was kind of my first exposure to this Mapbox GL JS React wrapper that we're using. Dropped in the link to that if anyone's interested. Anyway, sorry, that was a tangent because that query was loaded in here. What we want is more a query like this. So let's say show me the first 10 properties, and then let's do a filter where the location distance is less than some value. So we had, oops. We had our latitude and longitude. Let's grab that. So because our map is centered around this area, let's just start off centered on this area. Oops, got an extra curly brace. And so let's say within two kilometers of that point. Filter open paren open paren. I probably have an extra closing parenthese. And there we go. So first let's just start off, bring in the address. And then we need the latitude and longitude. So location, latitude, and longitude. So Tomas says, "Is there any demo app with GraphQL subscriptions available?" Yeah, that's a good question. I'm trying to think. So I know that there's nothing kind of out of the box that we've done with subscriptions yet in Neo4j GraphQL JS. I know that some users have had some luck integrating subscriptions by adding pub/sub to Neo4j GraphQL.js. There are a few ways to do that, one either by just sort of triggering an event when there's a mutation, or also by using database triggers to publish. I'm not aware of any public demo apps that use that. We should put that on the list. Or maybe, Tomas, if that's something that you wanna take a stab at, I'm sure that would be super useful. But yeah, maybe we can add that functionality to our real estate app at some point. But yeah, good question. So for our query here, we want the address, the latitude and longitude. Maybe that's enough to pull in initially. I don't know, maybe we have subdivision, as well. Maybe that would be good to pull in subdivision name. And I guess eventually, we wanna, well, we wanna show detailed information. So we want number of bedrooms, number of full baths, number of half baths. square footage. Okay, so some of these, yeah, looks like we have data for most of these properties. Cool, so this is a good sort of query to start us off. So what we wanna do now, we wanna run this query to fetch some property listings, and then we wanna show this on the map with a marker, and then when you click on one of those markers, show you this detailed information about the property. So let's see how to do that. So that's gonna go in our search component. So right now, our search component is just sort of this dumb container that is just rendering our map results container component. So we've seen how to use the Apollo React hook for fetching data, which is now what we're going to do. So to use this, we want to first pull in the gql template tag from graphql-tag. So this is what is responsible for parsing a string representation of a GraphQL query. So let's call this property search query equals gql and paste in our GraphQL query. And it's also nice, in VS code, we get some nice syntax highlighting of our GraphQL query. And then we also want to pull in the use query Apollo React hook from Apollo React hooks, I think it is. And then the first thing we wanna do inside our component is call that use query hook, and we get back the different states. So loading, error, and then when it's done, data, and call use query and pass in our, what did we call it? Property search query. Okay, and we need to check if there's an error. Well, we're just going to, let's just return the word error instead of rendering our map and the search results. And if we're still loading, then we'll just say still loading. But then if we have data, what do we do with the data? Well, in this case, let's just pass that through. And we'll just say properties. So we're gonna pass this as a prop. It's gonna be data.Property. So if you look at our GraphQL query, actually, we can look at this in GraphQL Playground. So this is the exact object that's gonna be in data. So data.Property is going to be an array of properties with this information. Cool, so then within map results, let's actually do something with props here. So now we should have within this component an array of property information, and we want to actually put these on the map as markers. So if we take a look in the docs here for React Map, take a look at markers. Here's how we draw a marker. First we have to define sort of the style for the marker. So it's styling this div. And in this case, this is a draggable marker. We want ours to not be draggable. That's fine. And I don't know if we need any text. Maybe we can just draw a circle or something. So let's jump back. So I think we need to start by importing this marker from React Map GL. So the default export is MapGL. We want this marker component. And then inside our map, so let's remove that ending slash there. We'll actually close that here. MapGL. And then here is where we're actually going to add a marker component. So first, let's just add one so we can make sure that we know how to add a marker, and then we'll see how to actually add markers from our data. So our marker takes a couple of props. It is going to take a longitude and a latitude. Let's just use the location that we have for Montana State University. So here's our latitude. And here's our little longitude. Okay, if we we take a look at the map now, I don't think we'll see anything. Even though there may be a marker here, and the reason for that is because we need to add a div. And in the example we saw, they defined some simple styles and did something like this in a defined style object. So we can go ahead and use that format that we were using that we saw from that documentation. So that's just this example. All right, so basically, there's some CSS rules to draw a rounded rectangle with a blue background. Let's just copy that. And then we're just adding those styles here. And here's our marker. Cool. That's probably a bit bigger than what we need. Let's tweak that a bit. How about instead of 10 padding, let's make that four. The color's probably fine. We do want the pointer, the cursor to change to a pointer when we highlight over it. Border radius. That's drawing sort of a circle, I think, at 50%, maybe? Let's try that. There we go. That's a bit better size. So we've got a circle for just a single point. Nothing happens when we click on it. That's fine. Okay, so we have these props here, though. Let's do something with that. So first off, let's just do console.log props dot, what did we call it? I think we actually passed something called properties. So props.properties. So let's just log that to the console to see what that looks like. JavaScript console. And we get back an array of 10 objects. Let me make that bigger, easier to see. Yeah. Cool, so we get back an array of 10 objects that have things like address, location latitude/longitude, bedrooms, full baths, and so on. So we wanna do is for every one of these 10, I wanna draw a marker on the map, and then when I click on it, I wanna show some detailed information about that. So to do that, instead of drawing now this single marker here, what we're gonna do is say props.properties.map. So we're gonna call map to sort of iterate over all of our properties array. And map takes a function. It's gonna give us the property and then the index of that property in the array. And then we're going to, here is where we're going to return our marker. So let's copy that out and add the marker up here. And this is complaining because we don't have a key prop. So when you do this sort of mapping over an array in React, it needs a unique value for the key prop for anything that you iterate over for performance reasons. That's why we pulled in the index values. So we'll just pass the index value as our key prop. Cool, so now the latitude and longitude are not going to be this hard coded value. It's going to be p.location.longitude. Similarly for latitude, p.location.latitude. And what's it complaining about? Identifier expected? Really? No, fake news. Okay. So here's our map. Cool, and so the first 10 properties we found were over here. Okay, so we've got properties on a map. That's cool. Now we need to show some detailed information when we click on these. I guess what we really want to happen is when you click on one of these, then maybe this detailed view on the right is populated with some information that has details about the property and some photos and so on. So to do this, what we're going to do is add an on click handler for our marker that we're adding. So for the marker, actually, let's do this not on the marker, but on the div. I'll say on click equals some function. And what do we wanna do here? Well, we want some function that we're gonna call, let's just say, let's call one that says set current property, and we're gonna pass p. So this will be the property object to this set current property function, which we haven't actually defined yet, so let's do that. So what is set current property going to do? Well, I guess what we need to do is keep track of the current property, and then we need to pass that to some component here to our detail view. So our detail view is going to be maybe just something that renders information about the currently selected property. Cool, so because we're using functional React components, we get to use the React use state hooks for working with state. So what we'll do is up at the top here, I will say current property and set current property equals use state, and then we need to set an initial value. So current property, this is going to be, we want this to be an object that represents the currently selected property that the user has clicked on. And then set current property is going to be the function that is called to update the value of the current property state variable, but it needs an initial value. So let's just set this equal to maybe the first property in this properties array. So initially, at this point, when we're rendering our map results component, remember we've already fetched data from the GraphQL API, and now we're rendering this component with the results of that GraphQL query. So we have a list of properties. We'll just pick the first one to be the current. So then in our detail view, initially, let's just say, let's render currentProperty.address and closing curly brace. Okay, so now if we load this, we should see our initial properties from the search results. Yep, they're over here, a bit off center. That's fine. Another thing we're gonna have to think about is as we move the map around, we need to change the bounds, choose center points that we're using to search for properties, but we'll worry about that later. And we can see already when this loads, we're displaying information about our currently selected property, which this is just the first one in the array. Let's take a look at that. So if we bring up the search console where we're logging these, yeah, the first one is 2049 South Rouse Avenue. So that's just the first one. But now if we click one of these, then we should be re-rendering the data here to show our detailed information about the property. So as we click these, we can see, yep, here's your detailed information. Oh, we have a visitor. It's Jenny Cat. Hi, Jenny Cat. You're very naughty jumping up on my desk. Come say hi to everyone. Jenny Cat likes to interrupt my working here. We'll play in a second. We're almost done. Okay, so what else do we wanna do here? Well, we also want to, and okay, here we're showing the address. Maybe we also wanna show some more information. Let's, we can style this a bit later. But we might want to show things like the number of bedrooms. And this is gonna be currentProperty.bedrooms. And then something similar for, what'd we say we had? Full baths, which I think is full_baths, and then half baths, currentProperty.half_baths. And then, oh, I guess also we have square footage. That's kind of important. Square feet is currentProperty.sqft, I think. Okay, let's give that an update. Okay, so we don't have any information for 2049 South Rouse Avenue. I guess we just don't have information in the database about that. So if we click on some of these others, we can see the data update. So yeah, some of these, we just don't have that information for it. If you remember a couple sessions ago, we wrote that scraper to scrape the property record cards, and some of these, it could be that there's not actually a building there. For some reason, maybe our scraper didn't get the data. Anyway, here we have added a map component to show us some search results, and we can start to view those on the map and view some detailed information about those properties. Cool, so that I think might be a good place to stop for the day. So just to kind of reiterate what we covered so far, we added this map component from Mapbox GL JS. Specifically, we're using this react-map-gl wrapper around Mapbox GL JS. We updated our app to use this GraphQL query in the search component using Apollo React hooks to fetch data around a certain location, display that as markers on our map, and then we can start to view some detailed information about those properties. Cool, so next time, I think we'll take a look at maybe how we can style this view a bit better and take a look at how we can add photos to this view. So we don't have any photos of all these properties, but I think what we should be able to do is stitch in the Mapillary API, stitch that into our GraphQL API. So if you're not familiar with Mapillary, it has a lot of crowdsourced images that are used to, first they're, it's used as part of OpenStreetMap. So has this whole group of folks that are going around taking pictures, uploading them to Mapillary, and then At the same time, that data gets updated to OpenStreetMap to improve mapping, and then Mapillary makes these images available through an API. So I think what we'll be able to do is for each property, we'll be able to use the Mapillary API to see if there are photos of that house that we can then show in this detail view. Anyway, that'll have to be a exercise for next time. I'll go ahead and push this code up to GitHub so you can can go ahead and check that out and follow along. Otherwise, thanks, everyone, for joining today, and we'll see you next week. Cheers.
Subscribe To Will's Newsletter
Want to know when the next blog post or video is published? Subscribe now!