From c82a82869ae056a48172f08d1e82522451c133d1 Mon Sep 17 00:00:00 2001 From: Tanner Linsley Date: Mon, 11 May 2020 10:26:11 -0600 Subject: [PATCH] fix(suspense): reset query status when error is thrown in suspense Fixes #468 --- package.json | 1 + src/tests/useMutation.test.js | 5 +++ src/tests/useQuery.test.js | 64 +++++++++++++++++++++++++++++++++++ src/utils.js | 3 ++ yarn.lock | 19 +++++++++++ 5 files changed, 92 insertions(+) diff --git a/package.json b/package.json index 4d62ed1a6f..c98ef197fc 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "prettier": "^1.19.1", "react": "^16.13.0", "react-dom": "^16.13.0", + "react-error-boundary": "^2.2.1", "rollup": "^1.32.0", "rollup-plugin-babel": "^4.3.2", "rollup-plugin-commonjs": "^10.0.0", diff --git a/src/tests/useMutation.test.js b/src/tests/useMutation.test.js index 2977bd7438..aed177cbbe 100644 --- a/src/tests/useMutation.test.js +++ b/src/tests/useMutation.test.js @@ -44,6 +44,9 @@ describe('useMutation', () => { }) it('should be able to reset `error`', async () => { + jest.spyOn(console, 'error') + console.error.mockImplementation(() => {}) + function Page() { const [mutate, mutationResult] = useMutation( () => { @@ -82,5 +85,7 @@ describe('useMutation', () => { fireEvent.click(getByText('reset')) expect(queryByTestId('error')).toBeNull() + + console.error.mockRestore() }) }) diff --git a/src/tests/useQuery.test.js b/src/tests/useQuery.test.js index 38f1fd570d..2c230b43d7 100644 --- a/src/tests/useQuery.test.js +++ b/src/tests/useQuery.test.js @@ -1,4 +1,5 @@ import { render, act, waitForElement, fireEvent } from '@testing-library/react' +import { ErrorBoundary } from 'react-error-boundary' import * as React from 'react' import { useQuery, queryCache } from '../index' @@ -806,4 +807,67 @@ describe('useQuery', () => { expect(queryFn).toHaveBeenCalledTimes(2) expect(memoFn).toHaveBeenCalledTimes(2) }) + + // https://github.com/tannerlinsley/react-query/issues/468 + it('should reset error state if new component instances are mounted', async () => { + let succeed = false + const mockError = jest.fn() + jest.spyOn(console, 'error') + console.error.mockImplementation(mockError) + + function Page() { + useQuery( + 'test', + async () => { + await sleep(10) + + if (!succeed) { + throw new Error() + } else { + return 'data' + } + }, + { + retryDelay: 10, + suspense: true, + } + ) + + return
rendered
+ } + + const rendered = render( + ( +
+
error boundary
+ +
+ )} + > + + + +
+ ) + + await waitForElement(() => rendered.getByText('error boundary')) + + expect(mockError).toHaveBeenCalledTimes(3) + + fireEvent.click(rendered.getByText('retry')) + + await waitForElement(() => rendered.getByText('rendered')) + + console.error.mockRestore() + }) }) diff --git a/src/utils.js b/src/utils.js index 414b7964a0..df9e24c2dc 100644 --- a/src/utils.js +++ b/src/utils.js @@ -129,6 +129,9 @@ export function useMountedCallback(callback) { export function handleSuspense(queryInfo) { if (queryInfo.config.suspense || queryInfo.config.useErrorBoundary) { if (queryInfo.status === statusError) { + setTimeout(() => { + queryInfo.query.state.status = 'loading' + }) throw queryInfo.error } } diff --git a/yarn.lock b/yarn.lock index 99f9eba67c..a24d3a069f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1514,6 +1514,13 @@ dependencies: regenerator-runtime "^0.13.2" +"@babel/runtime@^7.9.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.6.tgz#a9102eb5cadedf3f31d08a9ecf294af7827ea29f" + integrity sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.1.0", "@babel/template@^7.4.4", "@babel/template@^7.6.0": version "7.6.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.6.0.tgz#7f0159c7f5012230dad64cca42ec9bdb5c9536e6" @@ -5994,6 +6001,13 @@ react-dom@^16.13.0: prop-types "^15.6.2" scheduler "^0.19.0" +react-error-boundary@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-2.2.1.tgz#32ed74386a90482060cc2fea948bb7135465c4cb" + integrity sha512-8SZMkJRFUb0JuluHKwuUtkh5vvVWBg3O/bJIWgNMhMJv529aG//TmcphR3cSMhCWjz1vFZDb4taJd6pmwP5mEQ== + dependencies: + "@babel/runtime" "^7.9.6" + react-is@^16.8.1: version "16.11.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.11.0.tgz#b85dfecd48ad1ce469ff558a882ca8e8313928fa" @@ -6084,6 +6098,11 @@ regenerator-runtime@^0.13.2: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw== +regenerator-runtime@^0.13.4: + version "0.13.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" + integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== + regenerator-transform@^0.14.0: version "0.14.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb"