I have really simple form wrapped in functional component. Everything worked even without forwardRef but console kept screaming:
my parent component:
import { useRef, useState } from 'react'
import './App.scss'
import { Stepper } from './stepper/Stepper.component';
import { Grid2 } from '@mui/material'
import { PersonalDetails, UserInfo } from './steps/PersonalDetails.component';
import { ContactDetails, ContactInfo } from './steps/ContactDetails.component';
export class UserDetails {
personalDetails: UserInfo = new UserInfo;
contactDetails: ContactInfo = new ContactInfo;
}
function App() {
const [activeStep, setActiveStep] = useState(0);
const [data, setData] = useState(new UserDetails)
const ref = useRef(null);
const handleBack = () => {
setActiveStep(activeStep-1)
console.log(activeStep)
}
const handleNext = () => {
setActiveStep(activeStep+1)
console.log(activeStep)
}
const updateFormData = (data: UserDetails) => {
setData((prevData) => {
console.log({...prevData, ...data})
return ({...prevData, ...data})
}) }
return (
<>
<div className="App">
<Grid2 container direction="row"
spacing={0.5}>
<Stepper activeStep={activeStep}/>
</Grid2>
{activeStep === 0 && (<PersonalDetails updateFormData={updateFormData} handleNext={handleNext} formData={data} ref={ref}/>)}
</div>
</>
)
}
export default App
my wrapped component looks like this:
import { Box, Button, Grid2, Input } from "@mui/material"
import { NEXT_BUTTON } from "../configuration/texts"
import { useForm, Controller } from 'react-hook-form';
import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayJS'
import { UserDetails } from "../App";
import { STEPS_INPUTS } from "../configuration/steps";
import { forwardRef } from "react";
import dayjs from "dayjs";
export class UserInfo {
firstName = "";
lastName = "";
dateOfBirth = dayjs(null);
}
export const PersonalDetails = forwardRef((
props: {
formData: UserDetails,
updateFormData: (data: UserDetails) => void,
handleNext: () => void
}, ref) => {
const { formData: { personalDetails } } = props;
const {
register,
control,
handleSubmit,
formState: { errors, isValid },
} = useForm<UserInfo>({
mode: 'onChange',
defaultValues: {
firstName: personalDetails.firstName,
lastName: personalDetails.lastName,
dateOfBirth: personalDetails.dateOfBirth,
}
});
const onSubmit = (data: UserInfo) => {
props.updateFormData({
...props.formData, personalDetails: data
})
props.handleNext()
}
return (
<>
<div ref={ref}>
<form onSubmit={handleSubmit(onSubmit)} style={{ width: '100%' }} >
<Grid2 sx={{ width: '100%', padding: '5px', borderColor: '#1769aa!important', borderRight: '1px solid', borderLeft: '1px solid', borderBottom: '1px solid' }} container direction="row" columns={12} spacing={0.5} >
<Grid2 size={2}><Box>First name:</Box></Grid2>
<Grid2 size={8}><Box><Input type="text" {...register('firstName', { ...STEPS_INPUTS.personalDetails.firstName })} style={{ width: '90%' }}></Input></Box></Grid2>
<Grid2 size={2}><Box>{errors.firstName && <span className="errorMsg">{errors.firstName.message}</span>}</Box></Grid2>
<Grid2 size={2}><Box>Last name:</Box></Grid2>
<Grid2 size={8}><Box><Input type="text" {...register('lastName', { ...STEPS_INPUTS.personalDetails.lastName })} style={{ width: '90%' }}></Input></Box></Grid2>
<Grid2 size={2}><Box>{errors.lastName && <span className="errorMsg">{errors.lastName.message}</span>}</Box></Grid2>
<Grid2 size={2}><Box>Date of birth:</Box></Grid2>
<Grid2 size={8}>
<Box>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Controller
control={control}
{...register('dateOfBirth')}
render={({ field: {onChange, value} }) =>
(<DatePicker
value={personalDetails.dateOfBirth.isValid() ? personalDetails.dateOfBirth : value}
onChange={onChange} />)}
rules={{
validate: { required: (value) => STEPS_INPUTS.personalDetails.dateOfBirth.required(value) }
}}
/>
</LocalizationProvider>
</Box>
</Grid2>
<Grid2 size={2}><Box>{errors.dateOfBirth && <span className="errorMsg">{errors.dateOfBirth.message}</span>}</Box></Grid2>
<Grid2 sx={{ width: '100%' }} container columns={2}>
<Grid2 size={1}></Grid2>
<Grid2 size={1}><Button variant="contained" disabled={!isValid} type="submit" sx={{ minWidth: '100%', marginTop: '20px' }}>{NEXT_BUTTON}</Button></Grid2>
</Grid2>
</Grid2>
</form>
</div>
</>
)
})
I have added forward ref but console still screaming. I think there is type problem in my code using ref inside wrapped component div.
Can anyone please help?
Thanks,
##EDIT
import { forwardRef } from "react";
interface Props {}
export const Solution = forwardRef<HTMLDivElement, Props>((props, ref) => {
return <div ref={ref}></div>;
});
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Controller
name="dateOfBirth"
control={control}
render={({ field: { onChange, value } }) => (
<DatePicker
value={value}
onChange={onChange}
/>
)}
rules={{
validate: {
required: (value) =>
STEPS_INPUTS.personalDetails.dateOfBirth.required(
value
),
},
}}
/>
</LocalizationProvider>