Skip to content

Instantly share code, notes, and snippets.

@JustAyush
Created February 1, 2022 09:55
Show Gist options
  • Save JustAyush/3b6984a41e70f20de1b87946062ebd84 to your computer and use it in GitHub Desktop.
Save JustAyush/3b6984a41e70f20de1b87946062ebd84 to your computer and use it in GitHub Desktop.
Dependent Inputs showcasing use of FormProvider
import {
Button,
FormControl,
FormErrorMessage,
FormHelperText,
FormLabel,
Link,
Select,
SimpleGrid,
Stack,
} from '@chakra-ui/react';
import { yupResolver } from '@hookform/resolvers/yup';
import React, { ReactElement } from 'react';
import {
Control,
FormProvider,
useForm,
useFormContext,
useWatch,
} from 'react-hook-form';
import * as yup from 'yup';
import SubmitDataDisplay from '../../components/submit-data-display';
import repos from '../../constants/repos';
const comicsOptions = ['DC', 'MARVEL'];
const DCSuperheroes = ['Superman', 'Batman', 'Wonder Woman', 'Flash'];
const MARVELSuperheroes = [
'Iron Man',
'Captain America',
'Captain Marvel',
'Spiderman',
];
type FormData = {
comics: string;
superhero: string;
};
const validationSchema = yup.object({
comics: yup.string().required('Comics is required'),
superhero: yup.string().required('Superhero is required'),
});
const defaultValues = {
comics: '',
superhero: '',
};
/**
* It is better to use `useWatch` to watch other formValue(s) in a separate component.
* This is because unlike getValues(), watch() triggers the component's re-render.
*
*/
const SuperheroSelect = ({ control }: { control: Control<FormData> }) => {
const {
register,
formState: { errors },
} = useFormContext<FormData>();
const comics = useWatch({
control,
name: 'comics',
});
const superHerosOptions = (() => {
switch (comics) {
case 'DC':
return DCSuperheroes;
case 'MARVEL':
return MARVELSuperheroes;
default:
return [];
}
})();
return (
<FormControl isInvalid={!!errors?.superhero}>
<FormLabel>Superhero</FormLabel>
<Select placeholder="Select option" {...register('superhero')}>
{superHerosOptions.map((item) => (
<option key={item} value={item}>
{item}
</option>
))}
</Select>
<FormHelperText>Please pick comics first.</FormHelperText>
<FormErrorMessage>
{errors?.superhero && errors?.superhero?.message}
</FormErrorMessage>
</FormControl>
);
};
function DependentInputs(): ReactElement {
const methods = useForm<FormData>({
resolver: yupResolver(validationSchema),
defaultValues: defaultValues,
});
const {
register,
handleSubmit,
formState: { errors },
control,
reset,
} = methods;
const onSubmit = (data: FormData) => {
alert(JSON.stringify(data));
};
const onReset = () => {
reset(defaultValues);
};
return (
<Stack spacing="10">
<SimpleGrid gap="10" columns={2}>
<FormProvider {...methods}>
<form onSubmit={handleSubmit(onSubmit)}>
<Stack spacing="6">
<FormControl isInvalid={!!errors?.comics}>
<FormLabel>Comics</FormLabel>
<Select placeholder="Select option" {...register('comics')}>
{comicsOptions.map((item) => (
<option key={item} value={item}>
{item}
</option>
))}
</Select>
<FormErrorMessage>
{errors?.comics && errors?.comics?.message}
</FormErrorMessage>
</FormControl>
<SuperheroSelect control={control} />
<Button colorScheme="primary" type="submit">
Submit
</Button>
<Button colorScheme="gray" onClick={onReset}>
Reset
</Button>
</Stack>
</form>
</FormProvider>
<SubmitDataDisplay control={control} />
</SimpleGrid>
<Link
href={repos.dependentInputs}
isExternal
color="primary.main"
_focus={{ outline: 'none' }}>
View Source
</Link>
</Stack>
);
}
export default DependentInputs;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment