fix(form): fix hydration error

was due to nested anchor tags
This commit is contained in:
zyachel 2023-05-21 18:13:44 +05:30
parent 8d9b6630a5
commit 8599ae2c5a
3 changed files with 40 additions and 47 deletions

View File

@ -25,16 +25,14 @@ const CardResult = ({ link, name, image, showImage, children, ...rest }: Props)
); );
return ( return (
<Card hoverable {...rest}> <Card hoverable {...rest} className={`${styles.item} ${!showImage && styles.sansImage}`}>
<Link href={link}> <div className={styles.imgContainer}>{ImageComponent}</div>
<a className={`${styles.item} ${!showImage && styles.sansImage}`}> <div className={styles.info}>
<div className={styles.imgContainer}>{ImageComponent}</div> <Link href={link}>
<div className={styles.info}> <a className={`heading ${styles.heading}`}>{name}</a>
<p className={`heading ${styles.heading}`}>{name}</p> </Link>
{children} {children}
</div> </div>
</a>
</Link>
</Card> </Card>
); );
}; };

View File

@ -5,41 +5,16 @@ import { QueryTypes } from 'src/interfaces/shared/search';
import { resultTypes, resultTitleTypes } from 'src/utils/constants/find'; import { resultTypes, resultTitleTypes } from 'src/utils/constants/find';
import styles from 'src/styles/modules/components/form/find.module.scss'; import styles from 'src/styles/modules/components/form/find.module.scss';
/**
* helper function to render similar radio btns. saves from boilerplate.
* @param data radio btn obj
* @param parentClass class under which radio input and label will be
* @returns JSX array of radios
*/
const renderRadioBtns = (
data: typeof resultTypes | typeof resultTitleTypes,
parentClass: string
) => {
return data.types.map(({ name, val }) => (
<p className={parentClass} key={val}>
<input
type='radio'
name={data.key}
id={`${data.key}:${val}`}
value={val}
className='visually-hidden'
/>
<label htmlFor={`${data.key}:${val}`}>{name}</label>
</p>
));
};
type Props = { type Props = {
className?: string; className?: string;
}; };
// MAIN FUNCTION
const Form = ({ className }: Props) => { const Form = ({ className }: Props) => {
const router = useRouter(); const router = useRouter();
const formRef = useRef<HTMLFormElement>(null); const formRef = useRef<HTMLFormElement>(null);
const [isDisabled, setIsDisabled] = useState(false); const [isDisabled, setIsDisabled] = useState(false);
// title types can't be selected unless type selected is 'title'. below is the logic for disabling/enabling titleTypes. // title types can't be selected unless type selected is 'title'
const typesChangeHandler: ChangeEventHandler<HTMLFieldSetElement> = e => { const typesChangeHandler: ChangeEventHandler<HTMLFieldSetElement> = e => {
const el = e.target as unknown as HTMLInputElement; // we have only radios that'll fire change event. const el = e.target as unknown as HTMLInputElement; // we have only radios that'll fire change event.
const value = el.value as QueryTypes; const value = el.value as QueryTypes;
@ -60,6 +35,7 @@ const Form = ({ className }: Props) => {
const queryStr = cleanQueryStr(entries); const queryStr = cleanQueryStr(entries);
if (query) router.push(`/find?${queryStr}`); if (query) router.push(`/find?${queryStr}`);
else setIsDisabled(false);
formEl.reset(); formEl.reset();
}; };
@ -87,22 +63,20 @@ const Form = ({ className }: Props) => {
name='q' name='q'
placeholder='movies, people...' placeholder='movies, people...'
className={styles.searchbar__input} className={styles.searchbar__input}
required
minLength={2}
/> />
<label className='visually-hidden' htmlFor='searchbar'> <label className='visually-hidden' htmlFor='searchbar'>
Search for anything Search for anything
</label> </label>
</p> </p>
<fieldset className={styles.types} onChange={typesChangeHandler}> <fieldset className={styles.types} onChange={typesChangeHandler}>
<legend className={`heading ${styles.types__heading}`}> <legend className={`heading ${styles.types__heading}`}>Filter by Type</legend>
Filter by Type <RadioBtns data={resultTypes} className={styles.type} />
</legend>
{renderRadioBtns(resultTypes, styles.type)}
</fieldset> </fieldset>
<fieldset className={styles.titleTypes} disabled={isDisabled}> <fieldset className={styles.titleTypes} disabled={isDisabled}>
<legend className={`heading ${styles.titleTypes__heading}`}> <legend className={`heading ${styles.titleTypes__heading}`}>Filter by Title Type</legend>
Filter by Title Type <RadioBtns data={resultTitleTypes} className={styles.titleType} />
</legend>
{renderRadioBtns(resultTitleTypes, styles.titleType)}
</fieldset> </fieldset>
<p className={styles.exact}> <p className={styles.exact}>
<label htmlFor='exact'>Exact Matches</label> <label htmlFor='exact'>Exact Matches</label>
@ -120,4 +94,28 @@ const Form = ({ className }: Props) => {
); );
}; };
const RadioBtns = ({
data,
className,
}: {
data: typeof resultTypes | typeof resultTitleTypes;
className: string;
}) => (
<>
{data.types.map(({ name, val }) => (
<p className={className} key={val}>
<input
type='radio'
name={data.key}
id={`${data.key}:${val}`}
value={val}
className='visually-hidden'
/>
<label htmlFor={`${data.key}:${val}`}>{name}</label>
</p>
))}
</>
);
export default Form; export default Form;

View File

@ -7,9 +7,6 @@
display: grid; display: grid;
grid-template-columns: var(--width) auto; grid-template-columns: var(--width) auto;
text-decoration: none;
color: inherit;
@include helper.bp('bp-450') { @include helper.bp('bp-450') {
--height: 15rem; --height: 15rem;
grid-template-columns: auto; grid-template-columns: auto;