FSA 1702 – March 28, 2017
- Make many requests, get your files
- Make a new request, get a new page
Views are stored on the server, served as HTML pages. Each page retrieves a new stylesheet etc.
Let's not render a new page each time.
- We make a
get
request to start - We click a link
- Instead of making a request and getting a full HTML page, we just get data back
- The front-end receives that data and slots it in properly, re-rendering the page to reflect that data
- The browser doesn't refresh
Instead of the server doing all the work,
We get our data with AJAX
.
We want url to change (superficially) so we can use the browser history, back and forward, and create the feel of multiple pages. (Browser History API)
- Keeps your UI in sync with the URL
- Ties into history/url for easy navigation
- Easily integrates nesting of components
A router is a URL and COMPONENT combined
<!-- localhost:3000/#/somepath/foo Everything after the # is ignored because the browser can't parse it!-->
<Router>
<Route path="/somepath" component={SomeComponent}>
<Route path="foo" component={FooComponent} /> <!-- When appended to somepath, we get a route -->
</Route>
<Route path="/otherpath" component={OtherComponent} />
</Router>
Back-end routes and front-end routes are very different! Don't confuse them.
Link
replaces a href
as a way navigate without going to a new page.
// Front-end
import React from 'react';
import ReactDOM from 'react-dom';
import {Route, Router, hashHistory, browserHistory, Link } from 'react-router';
class App extends React.Component {
render() {
return (
<div>
<h1> Here is the main app </h1>
<ul>
<li><Link to="/puppies">puppies</Link></li>
<li><Link to="/kittens">kittens</Link></li>
</ul>
{this.props.children} // Will render the children from this parent route
</div>
)
}
}
// Our backend has routes to return JSON for our puppies
class Puppies extends React.Component {
constructor (props) {
super(props);
this.state = {
puppies: []
}
}
componentDidMount () {
axios.get('/api/puppies')
.then(res => res.data)
.then(data => {
this.setState({
puppies: data
})
})
}
render() {
return (
<div> Here are the puppies </div>
{this.state.pupies.map(puppy => {
return {
<div key={puppy.id}>
<Link to={`/puppies/${puppy.id}`}>{puppy.name}</Link>
</div>
}
})}
{this.props.children && cloneElement(this.props.children, {
puppies: this.state.puppies
})} // If there are props children, we want to clone this.props.children, and then pass down the props object we want. cloneElement returns a copy of our element with props added!
)
}
}
class Puppy extends React.Component {
constructor(props) {
super(props),
this.state = {
selectedPuppy = {}
}
}
componentDidMount () {
axios.get(`api/puppies/${this.props.params.id}`)
.then(res => res.data)
.then(data => {
this.setState({selectedPuppy: data})
})
}
componentWillReceiveProps (nextProps) {
axios.get(`api/puppies/${this.nextProps.params.id}`)
.then(res => res.data)
.then(data => {
this.setState({selectedPuppy: data})
})
}
render() {
const {name, image} = this.state.selectedPuppy;
return (
<div>
<h1>{name}</h1>
<img src={image} alt=""/>
</div>
);
}
}
ReactDOM.render (
<Router history={hashHistory}>
<Route path='/' component={App}>
<Route path='/puppies' component={Puppies}>
<Route path='/puppies/:id' component={Puppy}></Route>
</Route>
</Route>
</Router>
document.getElementById('app');
)