I’m trying to make sure that Next.js doesn’t display the error, but rather I handle it on my code. I’m using Apollo-client to handle errors and I’m closely following the docs to make sure that I’m handling them properly. I’m currently getting a "Unhandled runtime error. Error: category already exists" displayed by Next.js, and on the Chrome browser console I’m getting a "Uncaught (in promise) Error: category already exists". However, I do notice that the error is showing up on my browser, but I just don’t want the Next.js error to show up.
I’ve tried to reorganize my code so that the error state doesn’t have to go through too many children components. I’ve tried to change the type of Error from UserInputError to ApolloError if category exists. I’m not sure what i’m doing wrong. Please help.
Here’s my code:
This is my code to get data from the backend:
const addCategory = async ({ user_id, name }) => {
await authorizeActivity({ user_id });
const categoryExists = await getCategory({ name, user_id });
if (categoryExists)
throw new UserInputError('The category name already exists');
const newCategory = await db
.insert({ user_id, name }, '*')
.into('category');
if (!newCategory[0]) {
throw new ApolloError('Something went wrong!');
}
return newCategory[0];
};
Here’s my page. Note that I pass my the error and loading states into the form component:
export default function NewCategory() {
const router = useRouter();
const user_id = Cookies.get('user');
const {
handleSubmit,
register,
formState: { errors, isDirty },
} = useForm();
const [addCategory, { data, loading, error }] = useMutation(ADD_CATEGORY);
useEffect(() => {
if (data) {
router.push('/user/menu');
}
}, [data]);
const onSubmit = (data) => {
addCategory({
variables: {
user_id,
name: data.category,
},
});
};
return (
<Layout>
<Form
formState={isDirty}
navigate={{
prev: {
message:
'Your changes will not be saved. Are you sure?',
link: '/user/menu',
},
}}
title={'Add new category'}
onSubmit={handleSubmit(onSubmit)}
button={
<button
type="submit"
style={{
padding: '16px 23px',
width: '100%',
maxWidth: '500px',
borderRadius: '8px',
marginTop: '10px',
}}
>
Add
</button>
}
state={{ loading, error }}
>
<Field
register={register('category', { required: 'Required' })}
info={{ name: 'category', label: 'Name' }}
errors={
errors.category
? errors.category.message
: errors.category
}
/>
</Form>
</Layout>
);
}
Here’s my form component:
export const Form = ({
onSubmit,
children,
title,
footer,
state,
button,
className,
navigate,
formState,
}) => {
const [warn, setWarn] = useState(false);
const [warnMessage, setWarnMessage] = useState({ toggle: setWarn });
const warning = ({ message, link, toggle }) => (
<Alert
pop
dismissible={() => toggle(false)}
state="warning"
message={
<>
{message}{' '}
<Link href={link} passHref>
<a
style={{
fontWeight: '400',
textDecoration: 'underline',
}}
>
Yes.
</a>
</Link>
</>
}
/>
);
return (
<>
{navigate ? (
<div className={styles.navigate}>
{navigate.prev && (
<RiArrowLeftCircleLine
onClick={() => {
if (formState) {
setWarnMessage({
...warnMessage,
...navigate.prev,
});
setWarn(!warn);
} else {
router.push(navigate.prev.link);
}
}}
/>
)}
{navigate.next && (
<RiArrowRightCircleLine onClick={navigate.next} />
)}
</div>
) : null}
{warn ? warning(warnMessage, setWarn) : null}
<div className={styles.form_wrapper}>
{(title && <div className={styles.form_title}>{title}</div>) ||
null}
<form
onSubmit={onSubmit}
className={`${styles.form_inner} ${className || ''}`}
>
{children}
{state &&
(state.loading || state.error || state.warning) ? (
<div className={styles.form_state}>
{state.loading ? (
<Loading />
) : state.error ? (
<Alert
state="error"
message={
state.error?.message ||
'Something went wrong'
}
/>
) : state.warning ? (
<Alert
state="warning"
message={state.warning.message}
/>
) : null}
</div>
) : null}
{button || null}
</form>
{(footer && (
<div className={styles.form_footer}>{footer}</div>
)) ||
null}
</div>
</>
);
};
2 Answers
To fix the issue, i looked into the apollo docs more: https://www.apollographql.com/docs/react/data/error-handling/
I set an error policy: ‘all’, to render error information and any partial results.
const [addCategory, { data, loading, error }] = useMutation(ADD_CATEGORY, {
errorPolicy: 'all',
onCompleted: (data) => {
if (data.addCategory) {
router.push('/user/menu');
}
},
});
I was able to see the error on the client side, silencing errors on the console and browser, and any errors from Next.js.