redux-autoloader
redux-autoloader copied to clipboard
A higher order component for declarative data loading in React and Redux.
redux-autoloader
A higher order component for declarative data loading in React and Redux.
Install
- Install via NPM
npm install --save redux-autoloader
- Register reducer in your root reducer
The reducer must be mounted at reduxAutoloader
.
import { reducer as reduxAutoloaderReducer } from 'redux-autoloader';
const rootReducer = combineReducers({
...
reduxAutoloader: reduxAutoloaderReducer,
...
});
- Register saga
import { saga as reduxAutoloaderSaga } from 'redux-autoloader';
...
sagaMiddleware.run(reduxAutoloaderSaga);
...
Peer dependencies
- react
- redux
- react-redux
- redux-saga
Try demo locally
git clone https://github.com/woltapp/redux-autoloader.git
cd redux-autoloader
npm install
npm start
What problem does the library solve?
Attaching an API end-point to a view is such a common task that we decided
to create a module to remove unnecessary boilerplate from most of the views
and to greatly speed up the development.
With redux-autoloader
you can decorate any component and automatically
load data from an API. The higher order component will provide you the props for
handling the state; whether it returned data, is currently loading or returned
an error. Moreover, the data can be automatically reloaded both periodically
or manually. The library removes the tedious work of writing the logic of
handling common request/success/failure state, registering refreshing
and cache invalidation.
Examples
Super simple data loader
import { reduxAutoloader } from 'redux-autoloader';
...
const ExampleComponent = ({
data, // provided by reduxAutoloader
error, // provided by reduxAutoloader
isLoading, // provided by reduxAutoloader
}) = (
<div>
{isLoading && 'Loading data'}
{error ? JSON.stringify(error) : (
<div>
Your data: {JSON.stringify(data)}
</div>
)}
</div>
);
const ConnectedComponent = reduxAutoloader({
name: 'example-loader-1', // A unique name for the loader
apiCall: yourDataFech, // A function that returns a promise
})(ExampleComponent);
Set cache expiration and prevent excessive page loads
const ConnectedComponent = reduxAutoloader({
name: 'example-loader-2',
apiCall: yourDataFech,
reloadOnMount: false, // Prevent triggering reload on mount, default: true
cacheExpiresIn: 60000, // Set cache expiration time: data will be
// loaded on mount after 1 minute even if reloadOnMount=false
})(ExampleComponent);
Set auto-refresh
const ConnectedComponent = reduxAutoloader({
name: 'example-loader-3',
apiCall: yourDataFech,
autoRefreshInterval: 5000, // Set loader to automatically refetch data every 5 seconds.
// Can be stopped by calling props.stopRefresh().
})(ExampleComponent);
Reload (refresh) when prop changes
const ConnectedComponent = reduxAutoloader({
name: 'example-loader-3',
apiCall: yourDataFech,
reload: (props, nextProps) => props.myProp !== nextProps.myProp, // Watch when `myProp`
// changes and reload
})(ExampleComponent);
API Documentation
reduxAutoloader(options, mapStateToProps)
takes options
(Object) as
first (required) argument and mapStateToProps
(Function) as second (optional) argument.
Options
-
name
(String|Function -> String): A unique name for the loader (string) or a function that returns a name. If you make multiple loaders with the same name, they will share the same data (state). - always required - example:name: 'all-users'
- example:name: props => `user-loader-${props.userId}`
-
apiCall
(Function -> Promise): A function that returns a promise, which is usually an API call. If you want to provide arguments for the function, simply wrap it in a function that getsprops
as an argument. If left undefined,reduxAutoloader
can be used simply as a connector to the data state. - example:apiCall: props => fetchUser(props.userId)
- default:undefined
-
startOnMount
(Bool): Control the behavior of the loader on mount. Set tofalse
if you do not want load on mount and you don't want to start autorefreshing automatically (ifautoRefreshInterval
is set). - default:true
(enable refresh on mount and start auto refreshing) -
autoRefreshInterval
(Number|Function -> Number): Provide an integer in milliseconds to define the interval of automatic refreshing. You can define also a function to return interval dynamically based on props. If set to0
orundefined
, automatic refresh won't be started. - default:0
(no auto refreshing) - example:autoRefreshInterval: props => props.interval
-
loadOnInitialize
(Bool): Control whether to load the data immediately after initialization (component mounted). - default:true
-
cacheExpiresIn
(Number): Set the data expiration time, leavy empty for no expiration. If set, cache expiration will be checked oncomponentWillMount
. Use withreloadOnMount: false
to e.g. prevent excessive page loads. - default:0
(no expiration) -
reloadOnMount
(Bool): Control whether reload is done always on component re-mount.- default:
true
- default:
-
resetOnUnmount
(Bool): Control whether to completely reset data-loader state on unmount.- default:
true
- default:
-
reload
(Function -> Bool): This function is run when the decorated component receives new props. The function takesprops
(current props) as first argument andnextProps
as second. When the function returnstrue
, it performs a refresh on the data loader. Compared toreinitialize
(below), this won't reset the loader state. - example:reload: (props, nextProps) => props.userId !== nextProps.userId
- default:() => false
- ! NOTE ! settingreload: () => true
or any other function that returns always true will cause an infinite loop (do not do this!) -
reinitialize
(Function -> Bool): This function is run when the decorated component receives new props. The function takesprops
(current props) as first argument andnextProps
as second. When the function returnstrue
, it resets the data loader; effectively re-mounting the component with a clean loader state. - example:reinitialize: (props, nextProps) => props.userId !== nextProps.userId
- default:() => false
- ! NOTE ! settingreinitialize: () => true
or any other function that returns always true will cause an infinite loop (do not do this!) -
pureConnect
(Bool): This library usesconnect()
fromreact-redux
under hood. SetpureConnect: false
if you wish to preventconnect()
from controlling component updates based on props.- default:
true
- default:
-
renderUninitialized
(Bool): Render wrapped component when the loader state has not yet been initialized.- default:
false
- default:
mapStateToProps
mapStateToProps
is an optional function to provide if you want to
select only some props of the loader state or wish to rename them.
Example:
const ConnectedComponent = reduxAutoloader(options, state => ({
isLoadingUsers: state.isLoading,
users: state.data,
}));
Props
Props provided to the wrapped component.
-
isLoading
(Bool):true
ifapiCall
is triggered and not yet resolved. -
isRefreshing
(Bool):true
if loader is auto-refreshing. -
data
(any): Resolved data received from the apiCall Promise. -
dataReceivedAt
(Number): Datetime as UNIX epoch when data was received. -
error
(any): Rejected data received from the apiCall Promise. -
errorReceivedAt
(Number): Datetime as UNIX epoch when error was received. -
refresh
(Function): Call to refresh (reload) data immediately. -
startAutoRefresh
(Function): Call to start auto-refreshing. TakesrefreshInterval
as first optional argument. Takesoptions
object as second argument. Setoptions={ loadImmediately: false }
to start refreshing but skip first load. -
stopAutoRefresh
(Function): Call to stop auto-refreshing.
License
MIT