react-sidechain
v0.1.1
Published
Async data/components loading side-chain for react-router and @reach/router...Supports code splitting and isomorphic
Downloads
3
Readme
react-sidechain
WIP
- Necessary async component loading in chain.
- Necessary data loading in chain.
- Can be used with react-router, @reach/router, may other router frameworks
- Server side render + Client side render + Single page transition
Usage
Server Side
import { SideChainProvider, SideChainConsumer, SideChainStore, withSideChain } from 'react-sidechain';
async function renderHTML() {
const store = createStore(); // redux store
const sideChainStore = new SideChainStore({
locals: {
dispatch: store.dispatch,
getState: store.getState,
},
hookNames: ['fetch', 'defer'],
location: '';
});
await sideChainStore.load(App);
const result = React.renderToString(
<Provider store={store}>
<SideChainProvider value={sideChainStore}>
<StaticRouter
location={req.url}
context={context}
>
<App sideChainStore={sideChainStore} />
</StaticRouter>
</SideChainProvider>
</Provider>
);
return result;
}
Client Side
import { SideChainProvider, SideChainConsumer, SideChainStore, withSideChain } from 'react-sidechain';
async function renderHTML() {
const store = createStore(); // redux store
const history = createBrowserHistory();
const sideChainStore = new SideChainStore({
locals: {
dispatch: store.dispatch,
getState: store.getState,
getPathname: () => history.location.pathname,
},
hookNames: ['fetch', 'defer'],
location: history.pathname;
});
await sideChainStore.load(App);
sideChainStore.setHookNames(['fetch', 'defer', 'done']);
// Load data in a side chain
history.listen(() => {
sideChainStore.setLocation(location.pathname);
sideChainStore.load(App);
});
const result = React.renderToString(
<Provider store={store}>
<SideChainProvider value={sideChainStore}>
<Router history={history}>
<App sideChainStore={sideChainStore} />
</Router>
</SideChainProvider>
</Provider>
);
}
import { matchRoutes, renderRoutes } from 'react-router';
const routes = [{
exact: true,
path: '/',
asyncComponent: () => import('./components/Home'),
}, {
path: '/about',
asyncComponent: () => import('./components/About'),
}, {
path: '/:user',
asyncComponent: () => import('./components/User'),
}, {
asyncComponent: () => import('./NoMatch'),
}];
async function defer({dispatch, getState, getPathname, load, setProps, getProps}) {
const matchedRoutes = matchRoutes(routes, getPathname());
const promises = matchedRoutes.map( async data => {
const { route } = data;
if (route.component) return data;
const { default: Component } = await route.asyncComponents();
// Load async component in chain
await load(Component);
route.component = Component;
});
await Promise.all(promises);
setProps({
routes,
});
}
function done({dispatch, getState, load}) {
// Only run on client side
// ...
}
@withSideChain({ defer, done })
class App extends React.Component {
static propTypes = {
routes: PropTypes.object,
}
render() {
return renderRoutes(this.props.routes);
}
}