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
getrequest 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');
)