react-use-rest
React.js data hooks for REST API endpoints
Purpose
Makes data fetching and CRUD operations against any REST endpoint this easy.
// create a data hook... this would likely be done elsewhere and imported hereconst useKittens = { let data: kittens isLoading = // use it, and store the results return <div>isLoading ? 'loading kittens...' : `we found kittens!`</div>}
Features
- auto-loading
- complete REST (GET/POST/PUT/PATCH/DELETE)
- collections, items in collections, or fixed endpoints
- polling
- transforming payloads
- filtering payload results
- queries (static via object, or dynamic via function)
- collections self-maintain after POST/PUT/PATCH/DELETE
- event handling for errors, after responses, and on authentication failures
- specify how to derive id from collection items (used to generate endpoints like /api/items/3)
- persist non-sensitive results to prevent load time waits (while still updating after fetch)
- data is shared across components without context or prop-drilling, thanks to use-store-hook
- GET requests shared using internal pooling to cut down on duplicate network requests
Examples
- basic
- all options/returns (until documentation details all params)
- chained hooks (loading details dynamically)
- creating hooks from props (dynamic hook generation)
- handling 401/Unauthorized
API
Options
Name | Type | Default | Description |
---|---|---|---|
axios | axios instance |
axios |
You can pass in a custom axios instance to use (for advanced usage with injected headers, etc) |
autoload | boolean |
true |
data will fire initial GET by default unless set to false |
fetchOptions | object |
undefined |
Options to be passed into fetch requests if using internal native fetch (e.g. { fetchOptions: { headers: { Authorization: 'foo' } } }) |
filter | function |
undefined |
filters data results into the "filtered" collection |
getId | function |
(item) => item.id |
how to derive item ID from a collection item (used for endpoint generation for PUT/PATCH/DELETE |
initialValue | object or array |
[] or undefined |
initial value of "data" return, [] if collection, undefined if ID endpoint |
interval | number |
undefined |
refresh collection every 5000ms (5s) |
isCollection | boolean | false` |
set to false to allow direct REST against a specific endpoint | |
log | boolean or function |
false |
if passed true , uses console.log for debug output, otherwise accepts any function |
mergeOnCreate | boolean |
true |
use response payload for newly created items |
mergeOnUpdate | boolean | true` |
use response payload for newly updated items | |
mock | boolean |
true |
simulate, but do not fire POST/PUT/PATCH/DELETE actions (for testing) |
onAuthenticationError | function |
undefined |
fired when calls return 401 or 403 (e.g. can redirect, etc) |
onCreate | function |
undefined |
fired when item is created successfully |
onError | function |
console.error |
fired on internal error, or response errors |
onLoad | function |
undefined |
fired when data is loaded successfully |
onRemove | function |
undefined |
fired when item is deleted successfully |
onReplace | function |
undefined |
fired when item is replaced successfully |
onUpdate | function |
undefined |
fired when item is updated successfully |
persist | boolean |
false |
will persist results to localStorage for fast delivery on page refresh |
query | object or function |
undefined |
can send fixed query params via object such as { isLive: true } or via a dynamically executed query function (executed at time of load/interval), such as () => ({ isLive: Math.random() > 0.5 }) |
transform | function |
undefined |
use to reshape your API payload (e.g. (data) => data.data.slice(0,2) |
Example 2
(all options/returns exposed)
// create a data hookconst useKittens = // any options may be included here for convenience { // instantiate data hook with options (all options may also be passed at time of creation [above]) let data = // data returned from API (defaults to empty array) filtered = // data, as filtered with filter function (options) responds to changes in filter or data isLoading // isLoading flag (true during pending requests) error // API error (if any) - this is key // random render-busting attr to explode into a component on data changes. Looks like { key: 123556456421 } update // PATCH fn(item, oldItem) - sends only changes via PATCH (if changed) replace // PUT fn(item, oldItem) - sends full item via PUT (if changed) remove // DELETE fn(item, oldItem) - deleted item create // POST fn(item, oldItem) - creates item load // refresh/load data via GET refresh // alias for load() = return <ul> data </ul> }
Example 3
(chained hooks, e.g. collection and item details)
// create a data hookconst useKittens = // any options may be included here for convenience = { // quick tip: { persist: true } loads cached content at page load, then fires the GET and updates // as necessary to prevent stale data let data: kittens = let selectedKitten setSelectedKitten = let data: kittenDetails = if isLoading && !collectionslength return <p>Loading...</p> return <div> kittens <h1>Payload</h1> JSON // will reload whenever selectedKitten changes </div> }
Example 4
(generate and load hook dynamically from props)
// create a curried function to dynamically return a data hook from a collection nameconst useCollectionItems = const ViewCollectionItem = { console // { collectionName: 'kittens', itemId: 3 } will generate a dynamic hook // with endpoint '/api/kittens', and passing in the itemId, will load the hook as an item // with endpoint '/api/kittens/3' let data: itemDetails = itemId return <div>item ? JSON : null</div>}
Example 5
(redirect to login on 401)
// create a data hook that might see a 401/Unauthorizedconst useKittens = { let data = // if loading /api/kittens would fire a 401, the app // redirects to /login with enough info to return once logged in return <div>isLoading ? 'loading kittens...' : `we found kittens!`</div>}
Changelog
- v1.9.0 - replaced internal use-store-hook with updated module location use-store to avoid deprecation notices
- v1.8.0 - decreased module size to 4.3k gzipped
- v1.7.3 - fix: re-embeds default Content-Type: application/json header
- v1.7.1 - converted from babel to rollup + typescript to decrease module size
- v1.7.0 - added
fetchOptions
option (allows for custom headers to be passed with hook requests) - v1.6.0 - removed
deepmerge
dependency (previously used for options merging)