In my functional component / page I've got a const/function that I pass error messages to, that then updates a couple of useState records and logs the error to the console. It looks like this:
const catchError = (e:any, message:string) => {
//throw new Error(e)
setMessage(message);
setLoading(false);
console.error(e);
};
I'd like to move this code to a hook(?) / helper file that will allow me to import it into any other component. This would mean I can use one centralised piece of code rather than writing the same code in multiple places and avoid the associated issues.
So, I've created a new catchError.tsx
file with the following content:
import { useState } from 'react';
const [ message, setMessage ] = useState("idle");
const [ loading, setLoading ] = useState(false);
export const catchError = (e:any, message:string) => {
//throw new Error(e)
setMessage(message);
setLoading(false);
console.error(e);
};
However, when I render this I get the following compile error:
Failed to compile
src/hooks/catchError.tsx Line 3:33: React Hook "useState" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function react-hooks/rules-of-hooks Line 4:33: React Hook "useState" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function react-hooks/rules-of-hooks
Search for the keywords to learn more about each error.
This is new territory for me, so I'm stumbling along trying to find a solution and would appreciate any input you could offer to resolve the issue.
Thanks.
(P.s. I'm quite new to react / typescript so apologies if my terminology is wrong. I welcome any corrections in this regard.)
CodePudding user response:
If you want to reuse hook logic (like useState) you can write your own custom hooks.
I believe something like so could work, though I am not completely sure how this would be used without more context.
import { useState } from 'react';
function useCatchError() {
const [ message, setMessage ] = useState("idle");
const [ loading, setLoading ] = useState(false);
const catchError = (e:any, message:string) => {
//throw new Error(e)
setMessage(message);
setLoading(false);
console.error(e);
};
return { catchError, message, loading };
}
And be used like
export function Foo() {
const {catchError, message, loading} = useCatchError();
try {
bar();
} catch (e) {
catchError(e, e.message);
}
return (
<div>
{message ? `Error: ${message}` : loading ? "Loading" : "Foo"}
</div>
);
}
More on custom hooks in the React Docs: https://reactjs.org/docs/hooks-custom.html