react-context-fetcher v2.0.10
React Context Fetcher
Simple and universal data fetching library for React using context to consume data. It supports server side rendering (SSR).
$ npm install --save react-context-fetcher
# or
$ yarn add react-context-fetcher
API
import React from 'react';
import { createDataFetcher } from 'react-data-fetcher';
// function fetching data
const getData = async () => fetch(/* ... */).then(res => res.json());
// use the factory to create your fetcher
const fetcher = createDataFetcher(getData);
// the fetcher is composed from HOCs and custom hooks
const {
// HOC working as a data Provider
withDataFetcher,
// HOC working as a data consumer
withData,
// custom hook working as a data consumer
useData,
} = fetcher;
const MyComponent = ({ loading, error, data }) => {
if (loading) {
return <p>currently fetching data...</p>;
}
if (error) {
return <p>ups something happen: {error}</p>;
}
return <p>got data: {data}</p>
};
export default withDataFetcher(MyComponent);
createDataFetcher(fetcher, options)
Factory to build a fetcher
object that includes two HOCs and one custom hook (cf. the previous code sample).
The factory may take options.
// factory options
{
// fetcher name
name: 'data',
// we may provide options for the providers
providerOptions: null,
// we may provide options for the consumers
consumerOptions: null,
}
The fetcher
's name is used when naming the HOCs & hook. If we were to give book
to this option, the resulting object would be withBook
, withBookFetcher
and useBook
.
The fetcher
option is the function that will be called whenever we want to fetch data.
const getData = (variables, props) => { /* ... */ };
It will receive both the computed variables and received props as arguments.
withDataFetcher(options | wrappedComponent)
It fetches data and manage their lifecycle, the whole state is given through props to children
but also dispatched through a react context.
// provider options
{
// variables (function or object)
variables: null,
// pure option
pure: true,
// should we refetch on props change
refetchOnPropChanges: false,
// function defining if there's a change on props
// default function comes from https://www.npmjs.com/package/shallowequal
shouldUpdate: shallowequal,
// we may want to process the fetched data
cleanData: null,
}
You may omit options to use this HOC right away on your component (ex: withDataFetcher(Component)
),
or you may provide the options first and retrieve the configured HOC to apply on your component (ex: withDataFetcher(options)(Component)
).
export default compose(
withDataFetcher({
variables: { x: 42 },
}),
/* ... other HOCs */
)(MyComponent);
The option variables
may be an function that will receive props as its first argument.
withDataFetcher({
variables: (props) => { /* ... */ },
})
The wrapped component will receive 3 props : loading
, error
and data
.
withData(options | wrappedComponent)
withData
is a very simple HOC that consumes the context provided by withDataFetcher
and sends it to props. There's a few options for this HOC.
// consumer options
{
// pure option
pure: true,
}
Like withDataFetcher
you may omit those options.
// with options
export default withData({ pure: false })(MyComponent);
// without options
export default withData(MyComponent);
useData()
useData
is a custom hook you can use to consume data in a functional component.
const MyComponent = () => {
const { loading, error, data } = useData();
/* ... */
};
Server Side Rendering
React Context Fetcher comes in with SSR support.
Server side
import React from 'react';
import { renderToString, renderToStaticMarkup } from 'react-dom/server';
import { renderWithData } from 'react-data-fetcher';
const Html = ({ children, data }) => (
<html>
<body>
<div id="root" dangerouslySetInnerHTML={{ __html: children }} />
<script dangerouslySetInnerHTML={{ __html: `window.__FETCHER_STATE__=${JSON.stringify(data)};` }} />
</body>
</html>
);
router.get('*', async (req, res, next) => {
try {
const [innerHtml, data] = await renderWithData(<App/>, renderToString);
const html = renderToStaticMarkup(<Html data={data}>{innerHtml}</Html>)
res.status(200);
res.send(`<!doctype html>\n${html}`);
res.end();
} catch(error) {
next(error);
}
});
Client side
import React from 'react';
import { render } from 'react-dom';
import { SSRProvider } from 'react-data-fetcher';
const root = document.getElementById('root');
const tree = (
<SSRProvider state={window.__FETCHER_STATE__}>
<App />
</SSRProvider>
);
render(tree, root);