A data fetch hook that stays out of your way.
npm install @pinkairship/use-data-fetchA data fetch hook that stays out of your way.
Several react hooks exist that allow you to fetch data from a server, but most of them do too much for you. This library takes the best part of the fetch hooks (consistent access, global config, easy use, etc.) and makes it as simple as possible.
This library is also accessibility friendly, allowing for easy setup to alert screenreaders when data is fetched. For more information on screenreaders, see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions.
Table of Contents
=================
* Install
* Usage
* useDataFetch
* useFetched
* useFetchedArray
* useFetchOnMount
* Additional Usage Information
* Caching data
* Caching Definition and Precedence Order
* How to Use Cached Calls
* Storing fetched data in state
* Screen Reader Alerts
* Listening for Request State Changes
* API
* Definitions
* DataFetchProvider
* useDataFetch
* useDataFetch methods
* Request Level Options
* useFetched
* useFetchedArray
* Caveats
* API
* useFetchOnMount
* Testing Your Application with useDataFetch
* Spying Data Fetching
* Development
* Testing
* Running Tests
* Contributing
* Troubleshooting
Table of Contents created by gh-md-toc
With npm
``bash`
npm install @pinkairship/useDataFetch
With yarn
`bash`
yarn add @pinkairship/useDataFetch
Wrap the tree you wish to add and remove messages with a DataFetchProvider:
`jsx`
function App() {
return
}
Then create a component that will hook into using the data fetch instance:
`jsxUser Id: ${data.user.id}
export function MakeGet({
show = ({ data }) => alert(),
}) {
const { get } = useDataFetch('/userinfo')
return (
This library defines multiple hooks that build on each other and use the
DataFetchProvider. They are defined below.
$3
useDataFetch is the basic building block hook of this library. The basic usage of useDataFetch:`jsx
import React, { useState } from 'react'import { DataFetchProvider, useDataFetch } from '../src'
function App () {
return (
)
}
function MakeGet () {
const { get } = useDataFetch('http://localhost/userinfo')
return (
type="button"
onClick={() => get().then(({data}) => alert(User Id: ${data.user.id})}) }
value="Make Get"
/>
)
}
`See
example/App.js for more examples of how to use the other type of http requests (POST, PUT, DELETE, PATCH, and a custom config).$3
useFetched is a hook that acts like useState but fetches the initial value from the server (if path provided), or allows you to create a value using the familiar useState functionality that will then provide functions to post, patch, etc the data to the server. The basic usage is as follows:`jsx
function UseManagedFetch() {
const [id, setId, , dataFetch] = useFetched('/echo/myId') return (
type="button"
onClick={() =>
setId({
id: nanoid(),
data: 'I am created without a trip to the server!',
})
}
value="Make Managed State Update without Server Trip"
/>
type="button"
onClick={() => dataFetch.post()}
value="Save to server as new entity"
/>
type="button"
onClick={() => dataFetch.put()}
value="Update entity after it has been created"
/>
{requestState}
{id.data}
)
}
`See
example/App.js for examples on how to use the other functions from datafetch.
$3
useFetchedArray is a hook that acts like useState but fetches the initial collection of values from a server. It supports the full lifecycle of items in a collection. The basic usage is as follows:`jsx
function UseManagedArrayFetch() {
const [ids, setIds, requestState, dataFetch] = useFetchedArray(
'/randomIds'
) return (
type="button"
onClick={() => dataFetch.post()}
value="Make Managed Array State Post"
/> ... (other calls from dataFetch)
{requestState}
{ids.map((id) => (
{id.data}
))}
)
}
`See
example/App.js for examples on how to use the other functions from datafetch.$3
useFetchOnMount handles the common use case of loading data on mount. Without useFetchOnMount, when fetching data on mount of a component is handled as follows:`jsx
function MakeGet () {
const updateStatefunc = updateStateFunc(somestate)
const { get } = useDataFetch('http://localhost/userinfo') useEffect(() => get.then(updateStateFunc).catch(onErrorHandler)))
...
}
`With preload:
`jsx
function MakeGet () {
const updateStatefunc = updateStateFunc(somestate)
const { get } = useDataFetch('http://localhost/userinfo', {
hookOptions: {
updateStateHook: updateStateFunc
}
}) const refetch = () => get()
...
}
`The advantages of this api:
1. Simplified onMount datafetch management
1. Greater control over refetching
1. More delcaritive naming of onMount fetching
All of the options used for the base
useDataFetch can be passed down in the hookOptions section (and all options defined at the same levels as before are handled the same way).See
example/App.js for more a more complete example.$3
There are a few features worth calling out specifically in the usage section.
#### Caching data
Caching data is useful if you have several components in your application that use the same data but it is inconvenient to pass that data using props. Setting a cache behavior allows you to setup a datafetch for an endpoint and then retrieve that same data only once for multiple components.
This behavior is used in other libraries like
react-relay and apollo where graphql calls are stored, except that the caching algorithm of this cache is just a simple last-recently-used cache and does not attempt to make any assumptions about your data and how to cache it.##### Caching Definition and Precedence Order
Caching can be set in three separate places (described in precedence order):
1. At the
get|post|put|patch|... level
1. At the useDataFetch level
1. At the DataFetchProvider levelIn other words, the caching level set at
DataFetchProvider is overridden by the caching level set at useDataFetch, which in turn is overridden by the caching level set at the actual request call.##### How to Use Cached Calls
To use cached calls, you can set the value at any of the level described and the cache will return the stored value for any call made to a url with the same path.
`jsx
import React, { useState } from 'react'import { DataFetchProvider, useDataFetch } from '../src'
function App () {
return (
)
}
// Makes a request to the server each time the button is pressed and will return
// a new randomId
function MakeUncachedGet () {
const { get } = useDataFetch('http://localhost/randomId', { useCache: false })
return (
type="button"
onClick={() => get().then(({data}) => alert(User Id: ${data.user.id})}) }
value="Make Get"
/>
)
}// A call made in either of these components will return the same user id even though
// the randomId is called in both
function MakeGet () {
const { get } = useDataFetch('http://localhost/randomId')
return (
type="button"
onClick={() => get().then(({data}) => alert(User Id: ${data.user.id})}) }
value="Make Get"
/>
)
}
function MakeOtherGet () {
const { get } = useDataFetch('http://localhost/randomId') return (
type="button"
onClick={() => get().then(({data}) => alert(User Id: ${data.user.id})}) }
value="Make Other Get"
/>
)
}
`#### Storing fetched data in state
* Note that this is primarily a concern of
useDataFetch and useFetchOnMount as the other hooks store the state for you internally (using this strategy).To store fetched data you will need to pass a configuration object to
useDataFetch that updates the state.`jsx
function MakeStoredGetFetch() {
// set state on the component using useDataFetch
const [ids, setIds] = useState([])
// to prevent refetching data on each rerender, you must wrap the
// the state update in a useCallback hook
const updateStateHook = useCallback(
// make sure to wrap the set state function in something that
// will be called after the data is retrieved
({ data: id }) => setIds([...ids, id]),
[ids]
)
const { get } = useDataFetch('/randomId', { updateStateHook }) return (
type="button"
onClick={() => get()}
value="Make Stored Get"
/>
{ids.map((id) => (
Created id: {id.id}
))}
)
}
`#### Screen Reader Alerts
To add screen reader alerts (which you should - read more here) pass in a function that accepts the message for the alert.
`jsx
function MakeGetWithSrAlert() {
const { get } = useDataFetch('/userinfo', {
alertScreenReaderWith: 'Messages Came',
}) return (
type="button"
onClick={() => get()}
value="Make Get And Alert Screen Reader"
/>
)
}
`#### Listening for Request State Changes
Many libraries will provide mechanisms to automatically detect the state that the request is in - retrieving data, was it a success, was it a failure. These state changes are useful to control the ui when fetching data.
You can listen to the request lifecycle of
useDataFetch by defining the requestStateListener function at either the hook level or the request level. These functions will pass a string only that defines the state (one of running|success(for success)|error(for error)).`jsx
function MakeGet() {
const [loading, setLoading] = useState('pending')
const { get } = useDataFetch('/userinfo', {
requestStateListener: setLoading,
}) return (
type="button"
onClick={() => get()}
value="Make Get - Success"
/>
Request State: {loading}
)
}
`API
The api for useDataFetch is pretty small intentionally - it isn't supposed to handle all use cases. If you want something that does more state management or handles automatic retries and caching behavior, this library may not be for you.
$3
There are is a need to define the levels that this document described. Often a setting set at one level can be overridden at a more granular level. The levels are as follows:
1. Provider level - this is the first level and defines the configuration set when making a
DataFetchProvider
1. Hook Level - this is the second level and defines the configuration set when using the useDataFetch hook. Settings here override the Provider level.
1. Request Level - this is the third level and defines the configuration set when making a request, ie get(). Settings here override the Provider and the Hook levels.$3
To use the DataFetchProvider, do the following:
`jsx
import { DataFetchProvider } from '@pinkairship/useDataFetch'// Wrap the components that your mount point is going to use
function App() {
return // children here
}
`Below is table of the props that can be passed into the provider:
| Prop | Type | Description |
| ---- | ---- | ----------- |
|
datafetchInstance | object | - The instance of the http fetch object to be used.
- This must conform to the axios request api (https://github.com/axios/axios#axios-api).
- If not provided will use an axios instance.
|
| axiosCreateOpts | object | - An object that conforms to the axios configuration api to be used when creating the dataFetchInstance.
- See https://github.com/axios/axios#request-config for more information. |
|
screenReaderAlert |function | - The function your app uses to alert screenreaders.
- The function will be passed the value of
alertScreenReaderWith.For more information, visit https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions. |
| makeMockDataFetchInstance | function | - A function that is used to wrap the dataFetchInstance calls for testing purposes.
- For example, the example app uses https://github.com/ctimmerm/axios-mock-adapter. |
|
useCache | boolean | - Use a cache for all calls made with this provider.
- Defaults to false.
- Can be overridden when defining the request methods, and also when making a request. |
|
cacheSize | number | - Set the number of items to keep track of before ejecting values from the cache.
- Defaults to 50.
- Cache is a last-recently-used cache. |
|
updateStateHook | function | - A function that updates the state you wish to house your fetched data.
- This function will be passed the responseData and the requestConfig -
(responseData, requestConfig) => {}. This hook is overridden if useDataFetch also defines updateStateHook.See the component in example/App.js for example of how it can be used. |
| debugCache | boolean | Attaches an array to window with key dataFetchCaches. Use this to see what value was is in the cache. |$3
To use the useDataFetch hook, do the following:
`jsx
import { useDataFetch } from '@pinkairship/useDataFetch'function MakeGet() {
// destructure the get function to request info from /userinfo
const { get } = useDataFetch('/userinfo')
return (
type="button"
// call the get function on click
onClick={() => get()}
value="Make Get"
/>
)
}
`Note that get does not make a request automatically when useDataFetch is called. This is intentional and breaks from the pattern of many other hooks that wrap data fetching. You will need to call your get in a
useEffect if you desire to have it fire on component load.`jsx
import { useEffect } from 'react'
import { useDataFetch } from '@pinkairship/useDataFetch'function MakeGet() {
// destructure the get function to request info from /userinfo
const { get } = useDataFetch('/userinfo')
useEffect(() => {
get()
})
return (
type="button"
// call the get function on click
onClick={() => get()}
value="Make Get"
/>
)
}
`Below is a table of the parameters for
useDataFetch:| Parameter | Type | Description |
| --------- | ---- | ----------- |
|
path | string | - The path to your resource.
- This can be a fully qualified url, or just the path instance if you configured your DataFetchProvider to use a baseUrl (see https://github.com/axios/axios#request-config for more information on the axios api).
|
| config | object | An object that accepts specific values. |The config parameter has a shape as follows:
| Configuration Key | Type | Description |
| ----------------- | ---- | ----------- |
|
updateStateHook | function | - A function that updates the state you wish to house your fetched data.
- This will override the
DataFetchProvider if it has defined the updateStateHook. |
|
alertsScreenReaderWith | any | - A message for the screenReaderAlert to read (see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions for more information).
- Note that your screenReaderAlert function can accept any type, so this also can be any type.
|
| requestConfig | object | An axios request configuration object (see https://github.com/axios/axios#request-config for more information on the axios api). |
| useCache | boolean | - Use the cache for all calls returned.
- Overrides the cache settings for the provider. Can be overridden by at the level that the call is made.
|
| requestStateListener | function | - Listen for the state changes in the request object
- This is a function that recieves a string dictating the state (one of
running\|success(for success)\|error(for error))Can be overridden at the request level. |#### useDataFetch methods
useDataFetch will return an object with functions ready to make your api requests.Available methods that
useDataFetch will generate are:| Method | Description | Usage | Notes |
| --- | ---- | -------- | -------- |
|
get | make a get request | get() | - Unlike axios, this does accept a data body
get(data, opts = {}).Note that undefined must be passed in to use the requestConfig without passing in data. To send query params: get(undefined, { requestConfig: { params: {} } }). |
| query | make a query (GET) request |query(params, opts = {}) | This is a nicer way of doing get(undefined, { requestConfig: { params: {} } }). |
| post | make a post request | post(data, opts = {}) | |
| put | make a put request |put(data, opts = {}) | |
| patch | make a patch request |patch(data, opts = {}) | |
| destroy | make a delete request| destroy(data, opts = {}) | |
| request | make a custom request |request(data, opts = {}) | - Note that this requires that you create a request config in your useDataFetch hook setup:
useDataFetch(undefined, { requestConfig: undefined (or some value) must be passed in first or else the requestConfig will not be registered and it will throw an error.For more infomration the axios request config, see https://github.com/axios/axios#request-config. You must include a url and a method in the requestConfig or an error will be thrown. |All of these methods return an axios request promise if you do not replace the http library with something else. This allows you control to chain after a request.
##### Request Level Options
The request level allows you to dynamically change a few of the options by defining behavior on the fly. These options override similar options defined at the hook level or the provider level.
| Option | Description |
| ------ | ----------- |
|
useCache | Use the cache for all calls returned |
| requestConfig | Used to send any last minute configuration, such as dymanically generated query params - { params: { id: '1234' } }. |
| requestStateListener | Listen for the state changes in the request object. This is a function that recieves a string dictating the state (one of running\|success(for success)|error(for error)). |$3
To use
useFetched, do the following (note that this still requires the DataFetchProvider wrapping the component at some higher level):`jsx
function UseManagedFetch() {
const [id, setId, requestState, dataFetch] = useFetched('/randomId') return (
type="button"
onClick={() => dataFetch.post()}
value="Make Managed State Post"
/> ... other datafetch requests
{requestState}
{id.data}
)
}
`You can also use this hook like a regular use state that has a direct hook to create via the given endpoint once it has been created:
`jsx
function UseManagedFetch() {
const [id, setId, , dataFetch] = useFetched('/randomId') return (
type="button"
onClick={() =>
setId({
id: nanoid(),
data: 'I am created without a trip to the server!',
})
}
value="Make Managed State Update without Server Trip"
/>
type="button"
onClick={() => dataFetch.post()}
value="Save to server as new entity"
/>
type="button"
onClick={() => dataFetch.put()}
value="Update entity after it has been created"
/>
{requestState}
{id.data}
)
}
`Note that the pattern for updating assumes that you use
POST to create a new entity from the route provided without the trailing id (ie /echo/myId would have a post path of /echo). There is a way around this as described below by using createUsesPath in the configuration.The following table describes the parameters passed into the hook:
| Parameter | Type | Description |
| --------- | ---- | ----------- |
|
path | string | - The path to your resource.
- This can be a fully qualified url, or just the path instance if you configured your DataFetchProvider to use a baseUrl (see https://github.com/axios/axios#request-config for more information on the axios api).
|
| config | object | An object that accepts specific values. |The config parameter has a shape as follows:
| Configuration Key | Type | Description |
| ----------------- | ---- | ----------- |
|
onSuccess | func | A callback to fire when the request is successful. Note that this is called after the updateStateHook is called (if defined) |
| onFailure | func | A callback to fire when the request is a failure. Fires after updateStateHook |
| hookOptions | object | The options for the underlying useDataFetch function. See the useDataFetch config options for more details. |
| createUsesPath | func | If your endpoints do not follow the convention described, you can pass in a function that will update the path to what it needs to be (ie (path) => /my/new/path) |
| cancelRequestOnUnmount | boolean | Cancels your fetch request if the react component is unmounted. False by default. |$3
To use
useFetchedArray, do the following (note that this still requires the DataFetchProvider wrapping the component at some higher level):`jsx
function UseManagedArrayFetch() {
const [ids, setIds, requestState, dataFetch] = useFetchedArray(
'/randomIds'
) return (
type="button"
onClick={() => dataFetch.post()}
value="Make Managed Array State Post"
/> ... (other calls from dataFetch)
{requestState}
{ids.map((id) => (
{id.data}
))}
)
}
`You can also add values to the array directly that are not persisted:
`jsx
function UseManagedArrayFetch() {
const [ids, setIds, requestState, dataFetch] = useFetchedArray(
'/randomIds'
) return (
type="button"
onClick={() =>
setIds([
...ids,
{
id: nanoid(),
data: 'I am created without a trip to the server!',
},
])
}
value="Make Managed Array State Update without Server Trip"
/> ... (other calls from dataFetch)
{requestState}
{ids.map((id) => (
{id.data}
))}
)
}
`#### Caveats
useFetchedArray makes a few assumptions about your data, namely that each item in your collection is an object and that it contains a field called id. It also assumes that you are using restful endpoints similar to the Ruby on Rails convention of storing resource ids in the path (ie /posts is the collection endpoint and /posts/:id is a specific resource in the collection).These caveats can be overcome by passing in a few configuration functions:
| Configuration Key | Description |
| ---------------- | ----------- |
|
transform | use this format data such that all values are an object and there is an id field present (and to transform any way you want). Note that you can also do this with axios (See https://github.com/axios/axios#request-config and the transformData configuration section for more information) |
| updatesUsePath | If your endpoints do not follow the convention described, you can pass in a function that will update the path to what it needs to be (ie if it stays the same, the function would be (path) => path) |
| extractObjectKey | If you have a key but it is not called id, you can pass in a function that will extract the correct key. ie. (data) => data.myKey |
| replaceValue | - If you have data that doesn't match the shape described (ie objects that have an id field) you can pass in your own replaceValue function when you do an update call.
- This will be called only on (
PUT\|PATCH)Example: ({data}) => { ...getdata; setValues(newData) // setValues output from hook def} |
| removeValue | Similar to replaceValue except it is used to remove the value on destroy only. See replaceValue for more details. |Also, only
get, post, put, patch, destroy are defined in the dataFetch object. If you require the flexibility provided by the full useDataFetch api, then this hook should not be used and useDataFetch should be used instead.The
destroy function is slightly changed - it has the following call signature: destroy(destroyData, removalKeys, opts). destroyData is the same as useDataFetch, removalKeys is the value (or values) of the id of the object that is being remove, and opts is the configuration opts for the underlying hook. If removalKeys is an array, then each value in the array is removed from the state.Example destroy call:
`js
// do not send any data, just remove this id
destroy(undefined, 'myId', {} //this last option can also be ommitted)// send data and remove this id
destroy({id: 'asd'}, 'foo')
// destroy multiple at once
destroy([{id: 'asd'}, {id: 'bsd'}], ['asd', 'foo'])
`#### API
The following table describes the parameters passed into the hook:
| Parameter | Type | Description |
| --------- | ---- | ----------- |
|
path | string | - The path to your resource.
- This can be a fully qualified url, or just the path instance if you configured your DataFetchProvider to use a baseUrl (see https://github.com/axios/axios#request-config for more information on the axios api).
|
| config | object | An object that accepts specific values. |The config parameter has a shape as follows:
| Configuration Key | Type | Description |
| ----------------- | ---- | ----------- |
|
onSuccess | func | A callback to fire when the request is successful. Note that this is called after the updateStateHook is called (if defined) |
| onFailure | func | A callback to fire when the request is a failure. Fires after updateStateHook |
| hookOptions | object | The options for the underlying useDataFetch function. See the useDataFetch config options for more details. |
| transform | func | use this format data such that all values are an object and there is an id field present (and to transform any way you want). Note that you can also do this with axios (See https://github.com/axios/axios#request-config and the transformData configuration section for more information). |
| updatesUsePath | func | If your endpoints do not follow the convention described, you can pass in a function that will update the path to what it needs to be (ie if it stays the same, the function would be (path) => path) |
| extractObjectKey | func | If you have a key but it is not called id, you can pass in a function that will extract the correct key. ie. (data) => data.myKey |
| replaceValue | func |- If you have data that doesn't match the shape described (ie objects that have an id field) you can pass in your own replaceValue function when you do an update call.
- This will be called only on (
PUT\|PATCH)Example: ({data}) => { ...getdata; setValues(newData) // setValues output from hook def} |
| removeValue | func | Similar to replaceValue except it is used to remove the value on destroy only. See replaceValue for more details. |
| extractList | func | This hook will extract data from an api get call if that data returned is a list or an object with a single root key whose value is a list. Other returned data will need to be transformed.
[{"id": ..}] is acceptable{"root":[{"id":...}]} is acceptable{"root":[{"id":...}], "otherKey":...} is NOT acceptable. You must define this function youself. |
| cancelRequestOnUnmount | boolean | Cancels your fetch request if the react component is unmounted. False by default. |
$3
To use
useFetchOnMount, do the following (note that this still requires the DataFetchProvider wrapping the component at some higher level):
`jsx
import { useFetchOnMount } from '@pinkairship/useDataFetch'function MakeGet() {
// destructure the get function to request info from /userinfo
const { get } = useFetchOnMount('/userinfo')
return (
type="button"
// call the get function on click
onClick={() => get()}
value="Refetch Get"
/>
)
}
`If you want to track the request data using some state tracking:
`jsx
import { useFetchOnMount } from '@pinkairship/useDataFetch'function MakeGet() {
// set state on the component using useDataFetch
const [ids, setIds] = useState([])
// to prevent refetching data on each rerender, you must wrap the
// the state update in a useCallback hook
const updateStateHook = useCallback(
// make sure to wrap the set state function in something that
// will be called after the data is retrieved
({ data: id }) => setIds([...ids, id]),
[ids]
)
// destructure the get function to request info from /userinfo
const { get } = useFetchOnMount('/userinfo', { hookOptions: updateStateHook })
return (
type="button"
// call the get function on click
onClick={() => get()}
value="Make Get"
/>
)
}
`useFetchOnMount returns the same object as useDataFetch, so all the same api applies here except that you will need to pass those options through the hookOptions key of the opts config. There are a few additional options that can be used when defining a useFetchOnMount request.| Parameter | Type | Description |
| --------- | ---- | ----------- |
|
path | string | - The path to your resource.
- This can be a fully qualified url, or just the path instance if you configured your DataFetchProvider to use a baseUrl (see https://github.com/axios/axios#request-config for more information on the axios api).
|
| config | object | An object that accepts specific values. |The config parameter has a shape as follows:
| Configuration Key | Type | Description |
| ----------------- | ---- | ----------- |
|
onSuccess | func | A callback to fire when the request is successful. Note that this is called after the updateStateHook is called (if defined) |
| onFailure | func | A callback to fire when the request is a failure. Fires after updateStateHook |
| hookOptions | object | The options for the underlying useDataFetch function. See the useDataFetch config options for more details. |
| cancelRequestOnUnmount | boolean | Cancels your fetch request if the react component is unmounted. False by default. |Testing Your Application with useDataFetch
For the most part testing your application while using
useDataFetch should be pretty straightforward - wrap whatever component you are using useDataFetch with a DataFetchProvider instance.`jsx
function makeMockAxios = () => {... creates a mock axios instance ...}function renderComponent(children) {
return render( // some render function for your testing library
{children}
)
}
test('my test', () => {
const component = renderComponent( )
... your test
})
`You can check out examples of testing in the
__tests__ folder for more information.$3
Sometimes you want to verify that a component makes a call with the correct data to your provider. This can be difficult with https://github.com/ctimmerm/axios-mock-adapter (the recommended mock library for axios).
In order to spy on a request, one approach is to create a mock that accepts a spy as the
dataFetchInstance of the DataFetchProvider.`jsx
function renderComponent(children, dataFetchProps = {}) {
return render( // some render function for your testing library
{children}
)
}test('creates a new thing', async () => {
let data
const dataFetchInstance = (requestData) => {
data = requestData
return Promise.resolve({ data: { message: { id: 1 } } })
}
const component = renderComponent( , { dataFetchInstance })
... your test
})
`By creating a data function that accepts the requestData normally passed into axios that in turn returns a promise, you match the api of axios. The
data variable can be set to the requestData and you can assert on the data being sent by any component using useDataFetch.Note that in this instance it assumes that your components will only make a single call. To capture the output of multiple calls, do the following:
`jsx
test('creates a new thing', async () => {
const data = []
const dataFetchInstance = (requestData) => {
data.push(requestData)
return Promise.resolve({ data: { message: { id: 1 } } })
}
const component = renderComponent( , { dataFetchInstance })
... your test
expect(data[0]).toEqual(..somedata)
expect(data[1]).toEqual(..somedifferentData)
})
`In a non-deterministic scenario (where it is unclear which order the calls will be made), it is recommended to filter for each call in the data array to perform your search (such as by the path of the data sent by axios):
`jsx
const firstExpectedCall = data.find((d) => d.url == 'expected/1')
const secondExpectedCall = data.find((d) => d.url == 'expected/2')
`Development
To run a development environment:
`
npm run start
`You can then navigate to
http://localhost:8080 and see the example app running. Using webpack serve, any changes you make to the src/ files will automatically be reflected.$3
Tests should be included in the
__test__ file. To help in writing tests, a wrapper
function has been provided in __tests__/test-utils.js. See __tests__/uncached-calls.js for examples on how to write tests.#### Running Tests
To run tests:
`
npm run test
`Contributing
- Keep it respectful
- Search issues for possible known issues (and help resolve them :))
- Always add some form of test (see Testing) to any pull requests (or make a case for why the change is already covered)
- Always update README.md with any new features/changes to behavior or usage.
- Update CHANGELOG.md with each pull request (unless it makes sense not to)
Troubleshooting
1. If you install into another project locally (using
npm install