react-page-loader-redux
v1.0.4
Published
`PageLoader` is a React Component that handles rendering your react-router routes.
Downloads
7
Readme
Page Loader
PageLoader
is a React Component that handles rendering your react-router routes.
It's built with the AppShell model in mind: Structuring your app in a way do that all pages share a common 'shell'.
Typically with an app-shell model, you only fetch the data you need for the current page - when the user navigates to a new page you then fetch the data / js /css for that page.
Here in lays the problem.
Co-ordinating this transition, so that you don't have to write lots of imperative code.
PageLoader
combines the following tools so you don't have to:
- react
- react-router
- redux
Usage
<PageLoader routes={routeConfig} ErrorPage={ErrorPage} OfflinePage= {OfflinePage} />
Route Config
Before you may have been rendering your routes like so:
<Router>
<Route exact path="/" component={HomePage} />
<Route exact path="/about" component={AboutPage} />
</Router>
With react-page-loader-redux
, we use react-router-config
to render the routes.
It take the routes, and an array of objects like so:
const routes = [
{
exact: true,
path: '/',
component: HomePage
},
{
exact: true,
path: '/about',
component: AboutPage
}
]
If you don't need to fetch data for a page, or the page component already exists in the app-shell js bundle then keep the config like above.
Fetching data for a page
If you need to fetch data before rendering a page do so by setting a fetcher
function in the route config:
const routes = [
{
path: '/info',
component: InfoPage,
fetcher: ({ match, route }) => { /* return a promise */}
}
]
The fetcher
will receive an object argument with the following keys:
match
: the matched route and it's paramsroute
: a reference to the route config object itself
The fetcher must return a promise - the promise should resolve the data required for that page.
PageLoader will handle the promise and store the data in redux under pageLoader.data
.
Fetching JS for a page
Now a days its common practice to split your JS into multiple bundles, since it's less JS to send down the wire and parse this is a nice perf boost for the end user.
We like react-loadable
for this use case:
cons loadable = require('react-loadable')
const routes = [
{
path: '/info',
component: loadable({
// using dynamic import
// webpack will automatically create this as a split point
// you can name the bundle using an inline comment
loader: import(/* webpackChunkName: "info-page" */'./pages/InfoPage'),
loading: <span>loading...</span>
}),
}
]
Server Side Rendering
- If you are using separate JS bundles, these bundles need to be loaded ahead of time before you render, or else you'd just get a 'loading' page.
- If you are using
react-loadable
then you can usepreloadAll().then(startServer)
- When the PageLoader boots up, it will detect the browsers location and begin fetching the required assets before trying to render that page. TODO Client JS logic for preloading.
AppShell Booting
- With service workers you can cache the app-shell html, and handle navigation requests allowing you to return the cached app-shell html instead of going to the network.
- The PageLoader can detect its booting via the app-shell, also being fetching the required assets before rendering the browsers location.
Client Side Transitions
- React-router's
<Link />
component handles updating the location and preventing the browsers default behaviour - PageLoader will handle fetching the assets before making the transition
Store props
TODO document integration
{
renderedRoute: Object,
isFetching: Boolean,
isOffline: Boolean
error: Error Object,
data: Object
}