Skip to content

Instantly share code, notes, and snippets.

@xialvjun

xialvjun/StackRoutes.jsx

Last active Jan 3, 2018
Embed
What would you like to do?
StackRoutes, make the router stacks like the modal, just agree with the history.
import React from 'react';
import { render } from 'react-dom';
import { BrowserRouter, Switch, Route, Link, withRouter, matchPath } from 'react-router-dom';
const db = {
authors: [
{ id: '8', name: 'xialvjun', gender: 'M', },
{ id: '1', name: 'lilei', gender: 'M' },
{ id: '7', name: 'hanmeimei', gender: 'F' },
],
posts: [
{ id: '3', title: 'i like javascript', author_id: '8' },
{ id: '2', title: 'i like rust', author_id: '8' },
{ id: '7', title: `it's sunny`, author_id: '8' },
{ id: '5', title: 'i like javascript too', author_id: '1' },
],
};
const Home = () => <div>
<h2>Home</h2>
<Link to="/authors/8">xialvjun</Link>
</div>;
const Author = ({ match, location, history }) => {
const author_id = match.params.author_id;
const author = db.authors.find(a => a.id === author_id);
if (!author) {
return <div><h2>Author with id: {author_id} doesn't exist.</h2></div>;
}
const posts = db.posts.filter(p => p.author_id === author_id);
const others = db.authors.filter(a => a.id !== author_id);
return <div>
<h2>name: {author.name}</h2>
<h6>gender: {author.gender}</h6>
<div>
<h4>posts:</h4>
<ul>{posts.map(p => <li key={p.id}>{p.title}</li>)}</ul>
</div>
<div>
<h5>others:</h5>
<ul>{others.map(o => <li key={o.id}><Link to={'/authors/' + o.id}>{o.name}</Link></li>)}</ul>
</div>
</div>;
};
const routes = [
{ path: '/authors/:author_id', component: Author },
{ path: '/', render: Home },
];
class StackRoutes extends React.Component {
constructor(props) {
super(props);
this.state = { locations: [props.location] };
this.max_layer = 5;
}
componentWillReceiveProps(nextProps) {
if (nextProps.location != this.props.location) {
if (nextProps.history.action === 'PUSH') {
const next_route = routes.find(r => !!matchPath(nextProps.location.pathname, r));
const this_route = routes.find(r => !!matchPath(this.props.location.pathname, r));
if (next_route != this_route) {
this.setState({ locations: this.state.locations.concat(nextProps.location).slice(-this.max_layer) });
} else {
const next_match = matchPath(nextProps.location.pathname, next_route);
const this_match = matchPath(this.props.location.pathname, this_route);
// console.log(next_match, this_match);
if (next_match.url !== this_match.url) {
this.setState({ locations: this.state.locations.concat(nextProps.location).slice(-this.max_layer) });
} else {
this.setState({ locations: this.state.locations.slice(0, -1).concat(nextProps.location).slice(-this.max_layer) });
}
}
} else if (nextProps.history.action === 'POP') {
this.setState({ locations: this.state.locations.slice(0, -2).concat(nextProps.location).slice(-this.max_layer) });
} else if (nextProps.history.action === 'REPLACE') {
this.setState({ locations: this.state.locations.slice(0, -1).concat(nextProps.location).slice(-this.max_layer) });
}
}
}
render() {
const { state: { locations } } = this;
// shouldn't use location.key because it will make normal push rebuild almost whole page
return locations.map((loc, i) => <Switch key={i} location={loc}>
{routes.map(route => <Route key={route.name} {...route}></Route>)}
</Switch>);
}
}
StackRoutes = withRouter(StackRoutes);
render(<BrowserRouter><StackRoutes/></BrowserRouter>, document.querySelector('#root'));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment