Hello, I am trying to globally handle some common errors instead of handling then per call, here is my strategie:
// my app
<SWRConfig value={swrConfigValue}>
<App />
</SWRConfig>
// swrConfigValue
export const swrConfigValue: ConfigInterface = {
fetcher,
onError: (err, key, config => {
switch (err.message) {
case 'Unauthorized':
history.push('/login');
break;
case 'Forbidden':
history.push('/forbidden');
break;
case 'PageNotFound':
history.push('/pageNotFound');
break;
default:
history.push('/maintenance');
}
},
};
// fetcher
export const fetcher = async (endpoint, initConfig) => {
const res = await fetch(endpoint , initConfig);
if (res.ok) {
return res.json();
} else {
throw new Error(res.statusText);
}
};
I am having an issue, as it tries to fetch 2 times...
overall I am not sure if it is a good strategie.
What do you think @sergiodxa @ryands17 @ranisalt?
Been looking to these issue as well https://github.com/zeit/swr/issues/329 https://github.com/zeit/swr/issues/131
I have seen that @shuding is working on https://github.com/zeit/swr/issues/325 , maybe you have some thoughts here?
What I usually do is to throw and handle that using an Error Boundary, there I navigate to another page if needed, also I use SWR with suspense enabled to be able to use error boundaries if the request fail, so I throw directly inside the fetcher function.
mind sharing a snippet?
Something like this
async function fetcher(url) {
const response = await fetch(url);
if (!response.ok) throw new Error(response.statusText)
return await response.json();
}
function CurrentUser() {
// any error we throw here will be caught by an error boundary
// rendered above in the component tree
const { data: user } = useSWR("/api/me", fetcher, { suspense: true });
// render something here
}
class ErrorBoundary extends React.Component {
state = { error: null };
static getDerivedStateFromError(error) {
return { error };
}
render() {
if (!this.state.hasError) return this.props.children;
// here we will handle the unauthorized error
if (error.message === "Unauthorized") {
Router.replace("/login"); // we navigate to login
return null; // and avoid rendering anything while login loads
}
// handle other errors or return some error UI
}
function App() {
// This error boundary will catch any error inside it
// The suspense boundary will handle the loading state
return (
<ErrorBoundary>
<React.Suspense fallback={<LoadingFallback />}>
<CurrentUser />
{/* probably more components here */}
</React.Suspense>
</ErrorBoundary>
)
}
I am having an issue, as it tries to fetch 2 times...
This is probably because shouldRetryOnError defaults to true right?
I personally wouldn't globally disable that since network errors do happen a lot.
You could try to create some custom behaviour that only retries on unhandled errors: https://github.com/vercel/swr#error-retries
I think we can close this issue since we now have https://swr.vercel.app/docs/error-handling and https://swr.vercel.app/docs/suspense :+1:
Most helpful comment
Something like this