Skip to content
Permalink
Browse files

fix: Preserve state if updateData is passed to useClientRequest. (#76)

### What does this PR do?
After updating the next.js example with the latest release we noticed that all our data would disappear when fetching more results. The way we recommend to do that is by updating the variables passed into `useQuery` and supplying an `updateData` method, which is responsible for merging the previous and new results. 

We previously merged a fix (#61) that resets state if variables or query changes in `useClientRequest`. The fix in this is to only reset the state if `updateData` is not set. This means that `state.data` is always populated after the initial request in this scenario.

### Checklist

- [x] I have checked the [contributing document](../blob/master/CONTRIBUTING.md)
- [x] I have added or updated any relevant documentation
- [x] I have added or updated any relevant tests
  • Loading branch information...
Joezo committed Feb 28, 2019
1 parent 545304c commit 4bf9e7301f241cdab49e32293fddd20bb6face1a
Showing with 73 additions and 1 deletion.
  1. +1 −0 src/useClientRequest.js
  2. +72 −1 test/unit/useClientRequest.test.js
@@ -72,6 +72,7 @@ function useClientRequest(query, initialOpts = {}) {
// in subsequent renders the operation could have changed
// if so the state would be invalid, this effect ensures we reset it back
React.useEffect(() => {
if (initialOpts.updateData) return; // if using updateData we can assume that the consumer cares about the previous data
dispatch({ type: actionTypes.RESET_STATE, initialState });
}, [JSON.stringify(cacheKey)]);

@@ -37,6 +37,77 @@ describe('useClientRequest', () => {
expect(state).toEqual({ cacheHit: false, loading: true });
});

it('resets data when query or variables change', async () => {
let fetchData;
let state;
const { rerender } = renderHook(
() => ([fetchData, state] = useClientRequest(TEST_QUERY)),
{
wrapper: Wrapper
}
);

// initial state
expect(state).toEqual({ cacheHit: false, loading: true });

await fetchData();

// populated with data for original query
expect(state).toEqual({
cacheHit: false,
loading: false,
data: 'data'
});

// operation has changed
mockClient.getCacheKey.mockReturnValueOnce('different key');

rerender();

// should be back to initial state
expect(state).toEqual({
cacheHit: false,
loading: true
});
});

it('does not reset data when query or variables change if updateData is set', async () => {
let fetchData;
let state;
const { rerender } = renderHook(
() =>
([fetchData, state] = useClientRequest(TEST_QUERY, {
updateData: () => {}
})),
{
wrapper: Wrapper
}
);

// initial state
expect(state).toEqual({ cacheHit: false, loading: true });

await fetchData();

// populated with data for original query
expect(state).toEqual({
cacheHit: false,
loading: false,
data: 'data'
});

// operation has changed
mockClient.getCacheKey.mockReturnValueOnce('different key');

rerender();

expect(state).toEqual({
cacheHit: false,
loading: false,
data: 'data'
});
});

describe('initial state', () => {
it('includes the cached response if present', () => {
mockClient.cache.get.mockReturnValueOnce({ some: 'cached data' });
@@ -216,7 +287,7 @@ describe('useClientRequest', () => {
});
});

describe('options.updateRequest', () => {
describe('options.updateData', () => {
it('is called with old & new data if the data has changed & the result is returned', async () => {
let fetchData, state;
const updateDataMock = jest.fn().mockReturnValue('merged data');

0 comments on commit 4bf9e73

Please sign in to comment.
You can’t perform that action at this time.