.bottom { padding: 0;
display: block;
z-index: 0;
color: var(--light-gray);
}
Now our <Sidebar /> with our <Listing /> component is complete.
Demo: Sidebar with Listings
Building the Main Pane
Now that we have our <Sidebar /> implemented, let’s build up our main elements. That is, let’s show our map and details. Since we’ll want these pages to be linkable, that is we want our users to be able to copy and paste the URL and see the same URL as they expect, we’ll set the main content to be defined by it’s URL.
In order to set these elements up to be handled by their routes, we’ll need to change our routes.
Currently, our routes are set by a single route that shows the <Container /> component. Let’s modify the route to show both a Map component and details.
Our src/views/routes.js file currently only contains a single <Route /> component. As a reminder, it currently looks like:
import React from 'react'
import {Route} from 'react-router' import Container from './Container' export const makeMainRoutes = () => {
return (
<Route path="" component={Container} />
) }
export default makeMainRoutes;
Let’s modify the makeMainRoutes() function to set the <Container /> component as a container (surprise) for the main routes.
export const makeMainRoutes = () => {
return (
<Route path="" component={Container}>
{/* child routes in here */}
</Route>
) }
Now, let’s build the <Map /> container we will surface in this area. We’ll build this <Map />
component in the src/views/Main/Map directory, so let’s import the exported component in our makeMainRoutes() file and list it as a child:
import Map from './Map/Map'
export const makeMainRoutes = () => {
return (
<Route path="" component={Container}>
<Route path="map" component={Map} />
</Route>
) }
Loading our new routes in the browser will show nothing until we navigate to the /map route AND we build our component. For the time being, let’s create a simple <Map /> component to show in the Map area to confirm the route is working.
As we’ve done a few times already, let’s create a JS file and the css module file in the src/views/Main/Map directory:
$ mkdir src/views/Main/Map
$ touch src/views/Main/Map/{styles.module.css,Map.js}
A really simple default <Map /> component with some dummy text is pretty simple to create
import React, { PropTypes as T } from 'react' import classnames from 'classnames'
import styles from './styles.module.css'
export class MapComponent extends React.Component { render() {
return (
<div className={styles.map}>
MAP!
Heading back to the browser, we’ll see that… wait, it’s blank? Why? We haven’t told the <Container /> component how or where to render it’s child routes. Before we can go much further, we’ll need to share our expectations with the component.
The React Way to handle this is by using the children prop of a component. The
this.props.children prop is handed to the React component when it mounts for any nodes that are rendered as a child of a React component. We’ll use the children prop to pass forward our child routes to be rendered within the container.
To use the children prop, let’s modify the <Container /> component in
src/views/Main/Container.js to pass them down inside the content block.
export class Container extends React.Component { // ...
render() { return ( <Map
visible={false}
className={styles.wrapper}>
<Header />
<Sidebar />
<div className={styles.content}>
{/* Setting children routes to be rendered*/}
{this.props.children}
</div>
</Map>
</div>
) } }
Now, when we load the view in the browser we’ll see that the route for /map inside the content block.
Since we are already loading the <Map /> container in the outer <Container /> component, we will already have a handle to the google reference as well as a reference to a created map instance. We can pass the reference down as a prop to the child elements by cloning children and creating a new instance to handle passing down data.
React makes this process easy to handle by using the React.cloneElement() function. In our render() method of the <Container /> component, let’s get a handle to the children props outside of the <Map /> component:
export class Container extends React.Component {
<div className={styles.content}>
{/* Setting children routes to be rendered*/}
With a handle to the children props, we can create a clone of them passing the new props down to the children, for instance:
export class Container extends React.Component { // ...
<div className={styles.content}>
{/* Setting children routes to be rendered*/}
Now, the children of the <Container /> component will receive the google prop. Of course, we also will have to pass the places from the state of the <Container /> component. We can pass any other data we want to send off within the React.cloneElement() function. We’ll pass as much data down as we need to here, which we’ll take advantage of a bit later.
export class Container extends React.Component {
<div className={styles.content}>
{/* Setting children routes to be rendered*/}
Now, we can update our <Map /> component (in src/views/Main/Map/Map.js) to show an actual
<Map /> from our GoogleApiComponent() container using the google props:
import React, { PropTypes as T } from 'react' import classnames from 'classnames'
import Map from 'google-maps-react' import styles from './styles.module.css'
export class MapComponent extends React.Component { render() {
return (
<Map google={this.props.google}
className={styles.map}
The <MapComponent /> here will work as expected as we are already creating the google component (in fact, we can also pass the map prop down and the GoogleApiComponent npm module will handle it correctly without creating a new map instance).