Reputation: 1024
I'm fairly new to React and I'm trying to get some dynamic content working based on a call to an API to validate some input data.
Because of the way I'm using the yup validation I think the code that handles the response from the API call has to be outside of the react function body. This means that I can't use "setOfferState" as shown in my example below.
I've tried doing it with just a basic variable "offer" and this seems to work OK most of the time, but I'm not convinced this will always work as I sometimes get errors in the console and have to reload the page. I understand that this is not the right way to set variables in React.
Both offer and offerState are shown in the example below, but offerState doesn't work (Error: Invalid hook call. Hooks can only be called inside of the body of a function component.)
let offer = '';
const [offerState, setOfferState] = useState(0);
const schema = yup.object().shape({
discount: yup.string().max(20).test('custom', null,
function (value) {
offer = '';
setOfferState('');
return new Promise((resolve, reject) => {
const api = new ApiFacade();
api.validateCode(value).then((result) => {
offer = result.value.offerDescription;
setOfferState(result.value.offerDescription);
})
})
})
});
const YourDetails = () => {
const formApi = useForm({
resolver: yupResolver(schema)
});
const { handleSubmit, setValue, trigger } = formApi;
return (
<FormProvider {...formApi}>
<form onSubmit={handleSubmit(onSubmit)}>
<Input name="discount" placeholder="Referral/Discount Code" />
<Button type="button" onClick={async () => { const result = await trigger("discount"); }}>Check</Button>
{/* {offer.length > 0 && ( */}
<Typography>{offer}</Typography>
<Typography>{offerState}</Typography>
{/* )} */}
<StepNav handleNext={handleSubmit(onSubmit)} />
</form>
</FormProvider>
);
};
export default YourDetails;
I would be grateful for any suggestions to resolve the state issue or how to move the validation code or validation response code into the function body.
Upvotes: 0
Views: 134
Reputation: 2604
Move your schema into the function body:
const YourDetails = () => {
let offer = '';
const [offerState, setOfferState] = useState(0);
const schema = yup.object().shape({
discount: yup.string().max(20).test('custom', null,
function (value) {
offer = '';
setOfferState('');
return new Promise((resolve, reject) => {
const api = new ApiFacade();
api.validateCode(value).then((result) => {
if (result.hasFailed) {
resolve(this.createError({ message: `Error checking code` }));
} else {
if (result.value.errorCode) {
resolve(this.createError({ message: result.value.errorMessage }));
} else {
offer = result.value.offerDescription;
setOfferState(result.value.offerDescription);
resolve(true);
}
}
})
})
});
const formApi = useForm({
resolver: yupResolver(schema)
});
const { handleSubmit, setValue, trigger } = formApi;
return (
<FormProvider {...formApi}>
<form onSubmit={handleSubmit(onSubmit)}>
<Input name="discount" placeholder="Referral/Discount Code" />
<Button type="button" onClick={async () => { const result = await trigger("discount"); }}>Check</Button>
{/* {offer.length > 0 && ( */}
<Typography>{offer}</Typography>
<Typography>{offerState}</Typography>
{/* )} */}
<StepNav handleNext={handleSubmit(onSubmit)} />
</form>
</FormProvider>
);
};
export default YourDetails;
Upvotes: 2