A set of react providers and components that allows for data to be used as a component, whether on the server or on the client.
yarn add data-hoc
- Async Loader Higher Order Components
- Opt In Server Side Rendering
You can import the generated bundle to use the whole library generated by this starter:
import React from 'react';
import { AsyncHoc } from 'data-hoc';
export const fetchJediQuery = (i) => fetch(`https://swapi.co/api/people/${i}/?schema=json`).then((res) => res.json());
export const FetchJedis = ({ params = {} }) => (
<AsyncHOC
name="FetchJedis"
params={params}
query={(ids) => Promise.all(ids.map(fetchJediQuery))}
>
{({ loading, error, data }) => <DisplayJedis jedis={data} />}
</AsyncHOC>
);
// /server/index.js
import express from 'express';
import universalLoader from './universal';
const app = express();
const PORT = process.env.PORT || 8081;
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.resolve(__dirname, '../build'), { index: false }));
app.use('*', universalLoader);
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}!`);
});
// /server/universal.js
import path from 'path';
import fs from 'fs';
import React from 'react';
import { StaticRouter } from 'react-router-dom';
import { SSRDataProvider, createSSRDataClient, renderToStringWithData } from 'data-hoc';
import App from '../src/App';
const filePath = path.resolve(__dirname, '../build/index.html');
const htmlData = fs.readFileSync(filePath, 'utf8');
const prepHTML = (html, { body, state }) => {
return html.replace('</head>', `<script>window.__SSR_DATA__=${JSON.stringify(state).replace(/</g, '\\u003c')}</script></head>`)
.replace(/<div id="root">.*<\/div>/, `<div id="root">${body}</div>`)
};
const universalLoader = (req, res) => {
const context = {}
const client = createSSRDataClient({}, { ssr: true });
const ServerApp = () => (
<SSRDataProvider value={client}>
<StaticRouter location={req.originalUrl} context={context}>
<App />
</StaticRouter>
</SSRDataProvider>
);
renderToStringWithData(client, ServerApp);
.then((body) => {
if (context.url) {
return res.redirect(301, context.url);
}
const state = client.extract();
const html = prepHTML(htmlData, {
state,
body
});
res.send(html);
})
.catch(e => {
res.send(htmlData);
});
};
export default universalLoader;
// /src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { SSRDataProvider, createSSRDataClient } from 'data-hoc';
import App from './App';
const initial = window.__SSR_DATA__ || {};
const client = createSSRDataClient(initial);
ReactDOM.render(
<SSRDataProvider value={client}>
<BrowserRouter>
<App />
</BrowserRouter>
</SSRDataProvider>
, document.getElementById('root'));
Made with β€οΈ by @rphansen91 and all these wonderful contributors (emoji key):
This project follows the all-contributors specification. Contributions of any kind are welcome!