redux-fetch-data
v0.1.4
Published
Redux utility library for fetching data using promises on both server and client.
Downloads
32
Readme
redux-fetch-data
Redux utility library for fetching data using promises on both server and client.
Install
npm install redux-fetch-data --save
Usage
Initial setup
On the server
Here is an example setup of a simple server. In this example we used Express, but any server framework will do.
import Express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { match, RouterContext } from 'react-router';
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { fetchDataOnServer, reducer as fetching } from 'redux-fetch-data';
import createHistory from 'react-router/lib/createMemoryHistory';
import routes from '../../routes';
const app = Express();
// Renders the actual HTML page
function renderHtml(html, state) {
return `
<!doctype html>
<html>
<body>
<div id="root">${html}</div>
<script dangerouslySetInnerHTML={{__html: `window.__INITIAL_STATE__=${JSON.stringify(state)};`}}
charSet="UTF-8"/>
</body>
</html>
`;
}
// Register the rendering middleware
app.use((req, res) => {
const history = createHistory(req.originalUrl);
const store = createStore(combineReducers({ fetching }));
match({ routes, location: req.url }, (err, redirect, renderProps) => {
// Fetch data
fetchDataOnServer(renderProps, store).then(() => {
// Data has been fetched, resolve request
if (err) {
res.status(500).send(err.message);
} else if (redirect) {
res.redirect(redirect.pathname + redirect.search);
} else if (renderProps) {
// Render the root component
const html = renderToString((
<Provider store={store} key="provider">
<RouterContext {...renderProps}/>
</Provider>
));
// Send the rendered page back to the client
res.status(200).send(renderHtml(html, store.getState()));
} else {
res.status(404).send('Not found.');
}
});
});
});
app.listen(3000);
On the client
Here is an example of a client-side entry script.
import React from 'react';
import { createStore, combineReducers } from 'redux';
import { render } from 'react-dom';
import { Router, browserHistory } from 'react-router';
import { Provider } from 'react-redux';
import { FetchData, reducer as fetching } from 'redux-fetch-data';
import routes from './routes';
// Hydrate the initial state from the server state
const initialState = window.__INITIAL_STATE__;
const store = createStore(combineReducers({ fetching }), initialState);
render(
<Provider store={store} key="provider">
<Router render={props => <FetchData {...props}/>}
history={browserHistory}
routes={routes}/>
</Provider>,
document.getElementById('root')
);
Fetching data
Instead of loading data in componentWillMount
, move that logic to a static fetchData
method.
This method should return a promise. Also, make sure you only fetch data from your containers
(top-level components), and pass down the data as props to sub-components.
export class Foo extends Component {
static fetchData() {
// this method should return a promise
}
.....
}
Protip! You can use Promise.all
to combine multiple promises into one.
Tests
Run the test suite:
npm test
Run the test suite in watch mode:
npm run test:watch <path>
Generate the code coverage report:
npm run test:cover
License
See LICENSE.