Incorporating defined Backbone models

"Next, let's define our index with how we need the routing to be and what paths should the routing respond to. From there, we will go ahead with building our components."

"Got it."

import React from 'react'
import { render } from 'react-dom'
import { createHistory, useBasename } from 'history'
import { Router, Route, IndexRoute, Link } from 'react-router'
import Backbone from 'backbone';
import Modal from './Modal'
import App from './App'
import { Cats, PictureModel } from './models';
import Picture from './Picture'
import Sample from './Sample'
import Home from './Home'

const history = useBasename(createHistory)({
  basename: '/pinterest'
});


render((
  <Router history={history}>
    <Route path="/" component={App}>
      <IndexRoute component={Home}/>
      <Route path="/pictures/:id" component={Picture}/>
      <Route path="/this/:cid/is/:randomId/sampleroute" component={Sample}/>
    </Route>
  </Router>
), document.getElementById('rootElement'));

"So, the first thing I see is that we are creating a session history?"

"Correct, we are creating a session history over here. We will use it for our router."

"Here, we are using the history module's useBasename method, which provides support for running an app under a base URL, which in our case is /pinterest."

"Got it."

"Next, we are laying out how we actually want the routing to be. We wrap our router into the <Router/> component and specify different <Route/> as paths."

"This is called the Route Configuration, which is basically a set of rules or instructions on how to match the URLs to some React Component in order to be displayed."

"Oh, can we discuss more about this configuration, it looks intriguing."

"It sure is. First, let's see what <IndexRoute component={Home}/> does. When we land on the / page for the application, which in our case would be /pinterest, the component defined by IndexRoute gets rendered. As you might have guessed, the component to be rendered is passed in the component argument of the route. Note that this is displayed in the App component that is the base component for all."

Similar to the IndexRoute, we have different <Route/> definitions. In our example, if you see <Route path="/pictures/:id" component={Picture}/>, it shows how route is getting used, and how we are passing attributes for the same. "Here, the path attribute is a matcher expression and component attribute specifies the component that is to be displayed after the route is matched."

"Notice how the path is defined over here, it is specified as an expression."

The matching for a route based on a URL is done on the basis of three components:

  • Nesting of route
  • Path attribute
  • Precedence of the route

Shawn began, "I got the nesting part. I see that we have arranged our routes in a nested fashion, like a tree. The route matching and building is being done on the basis of this tree-like matching structure."

"Right. Secondly, we have the path attribute. We can see examples for these:"

      <Route path="/pictures/:id" component={Picture}/>
      <Route path="/this/:cid/is/:randomId/sampleroute" component={Sample}/>

"The path value is a string that acts as a regex, which can consist of the following parts:"

  • :paramName: For example, ID, which is the param passed in the URL such as /pictures/12. 12 gets parsed as param id.
  • (): This can be used to specify an optional path, such as /pictures(/:id), this will match /pictures as well as /pictures/12.
  • *: As in case of regular expressions, * can be used to match any part of the expression, until the next /, ?, or # occurs. For example, to match all the JPEG images, we can use /pictures/*.jpg.
  • **: Greedy matching, similar to *, but it matches greedily. For example, /**/*.jpg will match /pictures/8.jpg as well as /photos/10.jpg.

"Got it. Finally, what remains is the precedence? Most probably, it should use the first route that is defined in the file and satisfy the condition used to match the path?"

"Exactly," Mike exclaimed.

"Oh, before I forget, we also have a <Redirect> route. This can be used to match some routes to other route actions. For example, we want /photos/12 to match /pictures/12 instead, we can define it as code."

<Redirect from="/photos/:id" to="/pictures/:id" />

"Awesome."

"Next, let's take a look at all the things that we are importing and using, which we will define as components."

import React from 'react'
…
import Modal from './Modal'
import App from './App'
import { Cats, PictureModel } from './models';
import Picture from './Picture'
import Sample from './Sample'
import Home from './Home'

"Let's define our App component first, which is going to act as the container:"

..
import { Router, Route, IndexRoute, Link } from 'react-router'
import Modal from './Modal'

const App = React.createClass({
  componentWillReceiveProps(nextProps) {
    if ((
            nextProps.location.key !== this.props.location.key &&
            nextProps.location.state &&
            nextProps.location.state.modal
        )) {
      this.previousChildren = this.props.children
    }
  },

  render() {
    let { location } = this.props;
    let isModal = ( location.state && location.state.modal && this.previousChildren );
    return (
        <div>
          <h1>Cats Pinterest</h1>
          <div>
            {isModal ?
                this.previousChildren :
                this.props.children
            }
            {isModal && (
                <Modal isOpen={true} returnTo={location.state.returnTo}>
                  {this.props.children}
                </Modal>
            )}
          </div>
        </div>
    )
  }
});

export {App as default}

"We aren't going to change much here, this is from the example that we have already seen."

"I see the use of location here. Is this from react-router?"

"As we saw, our App is wrapped into the router. The router passes in the location object from the props. The location object is actually similar to window.location and it is something the history module that we use defines. The Location object has various special attributes defined on top of it, which we are going to make use of, as follows:"

  • pathname: The actual pathname of the URL
  • search: The query string
  • state: A state passed on from the react-router and tied as an object to the location
  • action: One of the PUSH, REPLACE, or POP operations
  • key: The unique identifier for the location

"Got it. I can see that we are making use of props.children we had seen before."

  componentWillReceiveProps(nextProps) {
    if ((
            nextProps.location.key !== this.props.location.key &&
            nextProps.location.state &&
            nextProps.location.state.modal
        )) {
      this.previousChildren = this.props.children
    }
  }

"We are storing the children and the previous screen onto the App object when the Modal is displayed, I guess," queried Shawn.

"Yup. We are first checking whether we are displaying a different Component by matching the key attribute of location. We then check whether the state attribute was passed on the location and whether the modal was set to true on state. We will be doing that in case of Modal display. Here's how we will pass the state onto a link:"

<Link … state={{ modal: true .. }}.. />

" We will take a look at the Link object when we use it for the images."

"Got it," said Shawn.

"Then I see that we are passing around the children props or rendering the previous layout, and then, displaying Modal on top of it if modal is clicked:"

           {isModal ?
                this.previousChildren :
                this.props.children
            }
            {isModal && (
                <Modal isOpen={true} returnTo={location.state.returnTo}>
                  {this.props.children}
                </Modal>
            )}

"Exactly! You are getting pretty good at this," Mike exclaimed.

"Now, let's see our main index page component, shall we?"

// home.js
import React from 'react'
import { Cats, PictureModel } from './models';
import { createHistory, useBasename } from 'history'
import { Router, Route, IndexRoute, Link } from 'react-router'

const Home = React.createClass({
  render() {
    let sampleCat = Cats.sample();
    return (
        <div>
          <div>
            {Cats.map(cat => (
                <Link key={cat.cid} to={`/pictures/${cat.cid}`} state={{ modal: true, returnTo: this.props.location.pathname }}>
                  <img style={{ margin: 10 }} src={cat.get('src')} height="100" />
                </Link>
            ))}
          </div>
          <p><Link to={`/this/${sampleCat.cid}/is/456/sampleroute`}>{`Interesting Details about ${sampleCat.get('name')}`}</Link></p>
        </div>
    )
  }
});

export {Home as default}

"So Shawn, we are first importing all the data that we generate in the Cats collection. We are going to loop over them and display the images with links to Modals. You can see this happening here:"

            {Cats.map(cat => (
                <Link key={cat.cid} to={`/pictures/${cat.cid}`} state={{ modal: true, returnTo: this.props.location.pathname }}>
                  <img style={{ margin: 10 }} src={cat.get('src')} height="100" />
                </Link>
            ))}

"Yup, I see that we are setting the key using cat object's cid from the backbone object. We had to attribute for the link, which is path to where it should be linked, I guess?"

"That's right. For every cat displayed, we have a unique dynamic route generated, such as /pictures/121 and so on. Now, as we want to display the enlarged cat when we click on it, we are passing modal: true to state on <Link/>."

"We are also passing a returnTo attribute that is related to the current path that we obtain from the current location.pathname. We will be using this returnTo attribute from state to set up back links on components. We will display one on the Modal so that we can get back to the home page when it's clicked and the Modal will be closed."

"Got it. I see we are also defining a link for the sample cat display page here:"

    let sampleCat = Cats.sample();
…
render(
…
          <p><Link to={`/this/${sampleCat.cid}/is/456/sampleroute`}>{`Interesting Details about ${sampleCat.get('name')}`}</Link></p>
…
);

"Yup, we are going to randomly feature a cat here. We will display the details about the cat on the sample page. Now, I want to show you how we are creating the link here:"

`/this/${sampleCat.cid}/is/456/sampleroute`

"Here, we are creating a nested random route, for example, this can match a URL, as follows:"

/this/123/is/456/sampleroute

"The 123 and 456 act as params for the location."

"Nice," followed Shawn. "Let me define the Modal? Let me reuse the one from the example."

import React from 'react'
import { Router, Route, IndexRoute, Link } from 'react-router'

const Modal = React.createClass({
  styles: {
    position: 'fixed',
    top: '20%',
    right: '20%',
    bottom: '20%',
    left: '20%',
    padding: 20,
    boxShadow: '0px 0px 150px 130px rgba(0, 0, 0, 0.5)',
    overflow: 'auto',
    background: '#fff'
  },

  render() {
    return (
      <div style={this.styles}>
        <p><Link to={this.props.returnTo}>Back</Link></p>
        {this.props.children}
      </div>
    )
  }
})

export {Modal as default}

"That's simple and straightforward, Shawn. We also need to define how we display the pictures. Let's define that."

import React from 'react'
import { Cats, PictureModel } from './models';

const Picture = React.createClass({
  render() {
    return (
        <div>
          <img src={Cats.get(this.props.params.id).get('src')} style={{ height: '80%' }} />
        </div>
    )
  }
});

export {Picture as default}

"To display the cat and fetch details about it, we are using the ID that we receive from params. These are sent to us on the params prop. We are then fetching the ID from the Cats collection."

Cats.get(this.props.params.id)

"Using the id prop, recall how we were sending the ID on the cat link that we defined as follows"

<Route path="/pictures/:id" component={Picture}/>

"Finally, let's take a look at how the sample component is used to display the cat information from the example:"

import React from 'react'
import { Cats, PictureModel } from './models';
import { createHistory, useBasename } from 'history'
import { Router, Route, IndexRoute, Link } from 'react-router'

const Sample = React.createClass({
  render() {
    let cat = Cats.get(this.props.params.cid);
    return (
        <div>
          <p>CID for the Cat: {this.props.params.cid}, and Random ID: {this.props.params.randomId}</p>
          <p>Name of this Cat is: {cat.get('name')}</p>
          <p>Some interesting details about this Cat:</p>
          <p> {cat.get('details')} </p>
          </p>
        </div>
    )
  }
});


export {Sample as default};

"With this, it looks like we are done! Let's see how it looks, shall we?"

"The index page looks neat."

Incorporating defined Backbone models

"Next, let's see how the Modal and the links look with the URL."

"The cat sure looks nice," chuckled Shawn.

Incorporating defined Backbone models

"Haha, yes."

Note

Notice the URL. On clicking, the modal link changed to the one on the anchor tag. We are on the same page and the modal is displayed.

"Finally, we have the sample page, where we display details of the cat. Let's see how it looks:"

Incorporating defined Backbone models

"Awesome!"

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset