-
-
Notifications
You must be signed in to change notification settings - Fork 10.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Code splitting and v4 #3968
Comments
I've been trying to do exactly the same thing and came up with a similar structure. However, I was trying to use the Webpack bundle-loader. I had the How are you handling certain routes needing the user to be logged in? I ended up making some HOCs similar to your |
What do you mean? Could you please provide a simple example? A store instance is required to inject both reducer and saga, so it could be
But I really think that react's context is a better option here.
At first glance I don't see a problem here. Tomorrow we'll continue experimenting with v4 and protected routes are in the list. |
I wound up slightly modifying the basic idea in https://github.com/jtmthf/react-router-match-async in my repo: // util/match-async.jsx
import React, {Component, PropTypes} from 'react';
import _ from 'lodash/fp';
import {Match} from 'react-router';
class MatchAsync extends Component {
static propTypes = {
getComponent: PropTypes.func.isRequired
}
displayName = 'MatchAsync';
state = {
RouteComponent: null
};
componentWillMount() {
this.getComponent();
}
shouldComponentUpdate(nextProps, nextState) {
const {RouteComponent: lastRouteComponent} = this.state;
const {RouteComponent: nextRouteComponent} = nextState;
if (!lastRouteComponent && nextRouteComponent) {
return true;
}
return false;
}
getComponent = () => {
const {getComponent} = this.props;
const maybePromise = getComponent();
if (_.isFunction(maybePromise.then)) {
maybePromise.then(RouteComponent => this.setState({RouteComponent}));
}
}
render() {
const {RouteComponent} = this.state;
const matchProps = _.omit(['getComponent'])(this.props);
return (
<Match {...matchProps} render={props => RouteComponent ? <RouteComponent {...props} /> : null} />
);
}
}
export default MatchAsync; Then in the views... <MatchAsync getComponent={async () => await System.import('./login')} pattern="/login" /> Login redirects and other jazz can be handled in the same way the documentation currently recommends. |
@rosendi, something roughly like this: 'routes/index.js'
const bundleCache = {};
// This gets called and passed into a `Loader` component similar to your `asyncContainer`.
function loadBundle(bundle, store) {
return new Promise((resolve, reject) => {
// Early exit if we've loaded this bundle before. Prevents sagas being added multiple times
if (bundleCache[bundle]) {
return resolve(bundleCache[bundle]);
}
try {
// Use the `bundle-loader` to automatically get all matching files and their imports
require('bundle!./' + bundle + '/entry')(c => {
setupBundle(c, store);
// Add to cache for next time
bundleCache[bundle] = c.default;
resolve(c.default);
});
} catch (err) {
reject(err);
}
});
}
// Asks each bundle for its reducers and sagas
function setupBundle(bundle, store) {
if (bundle.getReducers) {
const newReducers = bundle.getReducers();
injectAsyncReducers(store, newReducers);
}
if (bundle.getSagas) {
const newSagas = bundle.getSagas();
injectAsyncSagas(newSagas);
}
}
// flow is from 'lodash/fp/flow'
const asyncAuthRoute = flow(loadBundle, loader, requireAuth); <-- auth is done here rather than in module/fractal
export const Routes = ({ store }) => (
<Match pattern="/some-url" component={asyncAuthRoute('some-bundle', store)} />
); Then one of the bundles might look like this: 'routes/some-bundle/entry.js'
import reducers from './reducers';
import { watchSagaOne, watchSagaTwo } from './sagas';
export default from './components/some-bundle'; <-- Main page. This would typically be a component with more `<Match>` components in it
export function getReducers() {
return {
someReducer: reducers
};
}
export function getSagas() {
return [
watchSagaOne,
watchSagaTwo
];
} The benefit of the I'm still working out if this is the best route to take or not. |
These solutions won't work with server side rendering. |
No, they won't. For that you'll need to follow something like this: https://medium.com/@apostolos/server-side-rendering-code-splitting-and-hot-reloading-with-react-router-v4-87239cfc172c#.jewws7git |
This is no longer in scope of this project, but if it should be possible and I'm sure people will figure out some great API that works with the router. As some patterns emerge, we should link to them from the docs, and maybe hint at some strategies. |
Here's the solution I built for those interested. It works with server side rendering too. |
@sheepsteak I wonder how would |
@pke there's a full example in react-boilerplate and you can see how they use it and set it up too. |
Today I tried to figure out how to refactor our huge application (~4000 modules) with amazing v4. We follow the fractal project structure and use a webpack's code splitting feature to reduce the initial bundle size. I didn't find a complete v4 example for that case usage, so I implemented it from scratch.
Let's say I have the following hierarchy:
First of all I imagined how a route definition could look like:
The
src/routes/campaigns/routes/reports/index.js
andsrc/routes/campaigns/routes/reports/view/ReportsView.js
components reflect the code above.Then I created a container in order to load components asynchronously and inject logic on demand:
Is the idea correct?
The text was updated successfully, but these errors were encountered: