react-context-fetcher
v2.0.10
Published
Factory to build provider and consumers to fetch data in React
Downloads
20
Readme
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);