Upgrade to React Router v4 (#667)
* Upgrade to React Router v4 * Fix pages not change when the URL was changed. This issue is due to the Redux `connect` wrapper around `<App/>`. `connect` diffs changes in regular props to know when to update the component, but doesn't check context props like `location`. See https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md. * Update to new `history` methods.
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from "react";
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import { IndexLink } from "react-router";
|
||||
import { Link } from 'react-router-dom';
|
||||
import { IconMenu, Menu, MenuItem } from "react-toolbox/lib/menu";
|
||||
import Avatar from "react-toolbox/lib/avatar";
|
||||
import AppBar from "react-toolbox/lib/app_bar";
|
||||
@ -66,9 +66,9 @@ export default class AppHeader extends React.Component {
|
||||
onLeftIconClick={toggleDrawer}
|
||||
onRightIconClick={this.handleRightIconClick}
|
||||
>
|
||||
<IndexLink to="/" className={styles.homeLink}>
|
||||
<Link to="/" className={styles.homeLink}>
|
||||
<FontIcon value="home" className={styles.icon} />
|
||||
</IndexLink>
|
||||
</Link>
|
||||
<IconMenu
|
||||
theme={styles}
|
||||
icon="add"
|
||||
|
@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { DragSource, DropTarget, HTML5DragDrop } from 'react-simple-dnd';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { Link } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import moment from 'moment';
|
||||
import { capitalize } from 'lodash'
|
||||
import { Card, CardTitle, CardText, CardActions } from 'react-toolbox/lib/card';
|
||||
|
@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { connect } from 'react-redux';
|
||||
import { IndexLink } from "react-router";
|
||||
import { Route, Switch, Link } from 'react-router-dom';
|
||||
import FontIcon from 'react-toolbox/lib/font_icon';
|
||||
import { Navigation } from 'react-toolbox/lib/navigation';
|
||||
import { Notifs } from 'redux-notifications';
|
||||
@ -21,6 +21,11 @@ import AppHeader from '../components/AppHeader/AppHeader';
|
||||
import { Loader, Toast } from '../components/UI/index';
|
||||
import { getCollectionUrl, getNewEntryUrl } from '../lib/urlHelper';
|
||||
import { SIMPLE, EDITORIAL_WORKFLOW } from '../constants/publishModes';
|
||||
import DashboardPage from './DashboardPage';
|
||||
import CollectionPage from './CollectionPage';
|
||||
import EntryPage from './EntryPage';
|
||||
import SearchPage from './SearchPage';
|
||||
import NotFoundPage from './NotFoundPage';
|
||||
import styles from './App.css';
|
||||
import sidebarStyles from './Sidebar.css';
|
||||
|
||||
@ -38,7 +43,6 @@ class App extends React.Component {
|
||||
|
||||
static propTypes = {
|
||||
auth: ImmutablePropTypes.map,
|
||||
children: PropTypes.node,
|
||||
config: ImmutablePropTypes.map,
|
||||
collections: ImmutablePropTypes.orderedMap,
|
||||
createNewEntryInCollection: PropTypes.func.isRequired,
|
||||
@ -104,7 +108,6 @@ class App extends React.Component {
|
||||
const {
|
||||
user,
|
||||
config,
|
||||
children,
|
||||
collections,
|
||||
toggleSidebar,
|
||||
runCommand,
|
||||
@ -140,7 +143,7 @@ class App extends React.Component {
|
||||
<section>
|
||||
<h1 className={sidebarStyles.heading}>Publishing</h1>
|
||||
<div className={sidebarStyles.linkWrapper}>
|
||||
<IndexLink to="/" className={sidebarStyles.viewEntriesLink}>Editorial Workflow</IndexLink>
|
||||
<Link to="/" className={sidebarStyles.viewEntriesLink}>Editorial Workflow</Link>
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
@ -193,7 +196,14 @@ class App extends React.Component {
|
||||
<div className={styles.entriesPanel}>
|
||||
{ isFetching && <TopBarProgress /> }
|
||||
<div>
|
||||
{children}
|
||||
<Switch>
|
||||
<Route exact path='/' component={DashboardPage} />
|
||||
<Route exact path="/collections/:name" component={CollectionPage} />
|
||||
<Route path="/collections/:name/entries/new" render={(props) => (<EntryPage {...props} newRecord={true}/>)} />
|
||||
<Route path="/collections/:name/entries/:slug" component={EntryPage} />
|
||||
<Route path="/search/:searchTerm" component={SearchPage} />
|
||||
<Route component={NotFoundPage} />
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -68,7 +68,7 @@ class CollectionPage extends React.Component {
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
const { collections, config } = state;
|
||||
const { name, slug } = ownProps.params;
|
||||
const { name } = ownProps.match.params;
|
||||
const publicFolder = config.get('public_folder');
|
||||
const collection = name ? collections.get(name) : collections.first();
|
||||
const page = state.entries.getIn(['pages', collection.get('name'), 'page']);
|
||||
@ -76,7 +76,7 @@ function mapStateToProps(state, ownProps) {
|
||||
const entries = selectEntries(state, collection.get('name'));
|
||||
const isFetching = state.entries.getIn(['pages', collection.get('name'), 'isFetching'], false);
|
||||
|
||||
return { slug, publicFolder, collection, collections, page, entries, isFetching };
|
||||
return { publicFolder, collection, collections, page, entries, isFetching };
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(CollectionPage);
|
||||
|
@ -56,11 +56,10 @@ class EntryPage extends React.Component {
|
||||
loadEntry(collection, slug);
|
||||
}
|
||||
|
||||
this.unlisten = history.listenBefore((location) => {
|
||||
this.unblock = history.block((location) => {
|
||||
if (this.props.entryDraft.get('hasChanged')) {
|
||||
return "Are you sure you want to leave this page?";
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@ -84,7 +83,7 @@ class EntryPage extends React.Component {
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.discardDraft();
|
||||
this.unlisten();
|
||||
this.unblock();
|
||||
}
|
||||
|
||||
createDraft = (entry) => {
|
||||
@ -161,9 +160,9 @@ class EntryPage extends React.Component {
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
const { collections, entryDraft } = state;
|
||||
const slug = ownProps.params.slug;
|
||||
const collection = collections.get(ownProps.params.name);
|
||||
const newEntry = ownProps.route && ownProps.route.newRecord === true;
|
||||
const slug = ownProps.match.params.slug;
|
||||
const collection = collections.get(ownProps.match.params.name);
|
||||
const newEntry = ownProps.newRecord === true;
|
||||
const fields = selectFields(collection, slug);
|
||||
const entry = newEntry ? null : selectEntry(state, collection.get('name'), slug);
|
||||
const boundGetAsset = getAsset.bind(null, state);
|
||||
|
@ -67,7 +67,7 @@ function mapStateToProps(state, ownProps) {
|
||||
const entries = selectSearchedEntries(state);
|
||||
const collections = state.collections.toIndexedSeq();
|
||||
const publicFolder = state.config.get('public_folder');
|
||||
const searchTerm = ownProps.params && ownProps.params.searchTerm;
|
||||
const { searchTerm } = ownProps.match.params;
|
||||
|
||||
return { isFetching, page, collections, entries, publicFolder, searchTerm };
|
||||
}
|
||||
|
16
src/root.js
16
src/root.js
@ -1,23 +1,21 @@
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { Router } from 'react-router';
|
||||
import routes from './routing/routes';
|
||||
import history, { syncHistory } from './routing/history';
|
||||
import { Route } from 'react-router-dom';
|
||||
import { ConnectedRouter } from 'react-router-redux';
|
||||
import history from './routing/history';
|
||||
import configureStore from './redux/configureStore';
|
||||
import { setStore } from './valueObjects/AssetProxy';
|
||||
import App from './containers/App';
|
||||
|
||||
const store = configureStore();
|
||||
|
||||
// Create an enhanced history that syncs navigation events with the store
|
||||
syncHistory(store);
|
||||
|
||||
setStore(store);
|
||||
|
||||
const Root = () => (
|
||||
<Provider store={store}>
|
||||
<Router history={history}>
|
||||
{routes}
|
||||
</Router>
|
||||
<ConnectedRouter history={history}>
|
||||
<Route component={App}/>
|
||||
</ConnectedRouter>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
|
@ -1,14 +1,5 @@
|
||||
import { createHashHistory } from 'history';
|
||||
import { useRouterHistory } from 'react-router';
|
||||
import { syncHistoryWithStore } from 'react-router-redux';
|
||||
import createHistory from 'history/createHashHistory';
|
||||
|
||||
let history = useRouterHistory(createHashHistory)({
|
||||
queryKey: false
|
||||
});
|
||||
let history = createHistory();
|
||||
|
||||
const syncHistory = (store) => {
|
||||
history = syncHistoryWithStore(history, store);
|
||||
};
|
||||
|
||||
export { syncHistory };
|
||||
export default history;
|
||||
|
@ -1,35 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Route, IndexRoute } from 'react-router';
|
||||
import App from '../containers/App';
|
||||
import DashboardPage from '../containers/DashboardPage';
|
||||
import CollectionPage from '../containers/CollectionPage';
|
||||
import EntryPage from '../containers/EntryPage';
|
||||
import SearchPage from '../containers/SearchPage';
|
||||
import NotFoundPage from '../containers/NotFoundPage';
|
||||
|
||||
export default (
|
||||
<Route path="/" component={App}>
|
||||
<IndexRoute component={DashboardPage} />
|
||||
<Route
|
||||
path="/collections/:name"
|
||||
component={CollectionPage}
|
||||
/>
|
||||
<Route
|
||||
path="/collections/:name/entries/new"
|
||||
component={EntryPage}
|
||||
newRecord
|
||||
/>
|
||||
<Route
|
||||
path="/collections/:name/entries/:slug"
|
||||
component={EntryPage}
|
||||
/>
|
||||
<Route
|
||||
path="/search/:searchTerm"
|
||||
component={SearchPage}
|
||||
/>
|
||||
<Route
|
||||
path="*"
|
||||
component={NotFoundPage}
|
||||
/>
|
||||
</Route>
|
||||
);
|
Reference in New Issue
Block a user