I have a form, which is part of a tabbed set of panels. The form itself looks like this:
import * as React from "react";
import { useForm, SubmitHandler, Controller } from "react-hook-form";
import { Char } from "../../models";
import { strikerTheme } from "../../../shared/components/StrikerTheme";
import ThemeProvider from "@mui/material/styles/ThemeProvider";
import TextField from "@mui/material/TextField";
import MenuItem from "@mui/material/MenuItem";
import InputAdornment from "@mui/material/InputAdornment";
import { useAppSelector } from "../../../../app/hooks";
import { getTraits, getIdeals } from "../../../shared/specSlice";
import { Quality } from "../../models/specs";
import { CheckboxGroup } from ".";
export const DescriptionForm = ({
onSubmit,
data
}: {
data: Partial<Char>;
onSubmit: SubmitHandler<Partial<Char>>;
}) => {
const specState = useAppSelector(state => state.specState);
console.log('imitial data')
console.log(data)
const { handleSubmit, control } = useForm({defaultValues: data});
const alignments = ['Lawful Good', 'Neutral Good', 'Chaotic Good', 'Lawful Neutral', 'Neutral', 'Chaotic Neutral', 'Lawful Evil', 'Neutral Evil', 'Chaotic Evil']
const traits: Quality[] = getTraits(specState.specKeys);
const ideals: Quality[] = getIdeals(specState.specKeys);
return data && (
<ThemeProvider theme={strikerTheme}>
<form className='form' onSubmit={handleSubmit(onSubmit)}>
<h4>Description</h4>
<div className='form-row'>
<Controller name="name" control={control} render={({ field }) => <TextField sx={{ width: '40ch' }} {...field} label="character name" />} />
</div>
<div className='form-row'>
<Controller name="experience" control={control} render={({ field }) => <TextField {...field} label="experience" />} />
<Controller name="levels" control={control} render={({ field }) => <TextField {...field} label="level" />} />
</div>
<div className='form-row'>
<Controller name="age" control={control} render={({ field }) => <TextField {...field} label="age" />} />
<Controller name="gender" control={control} render={({ field }) => <TextField {...field} label="gender" />} />
<Controller name="height" control={control} render={({ field }) => <TextField {...field} label="height" />} />
<Controller name="weight" control={control} render={({ field }) =>
<TextField {...field} label="weight" InputProps={{
endAdornment: <InputAdornment position="end">kg</InputAdornment>,
}}
/>}
/>
</div>
<div className='form-row'>
<Controller
name="alignment"
control={control}
render={({ field }) => <TextField {...field} label="alignment" helperText="Please select your alignment" select>
{alignments.map((option) => (
<MenuItem key={option} value={option}>
{option}
</MenuItem>
))}
</TextField>}
/>
<div className='form-row'>
<Controller name="traits" control={control} render={({ field }) => <CheckboxGroup
control={control}
label="traits"
options={traits}
{...field}
/>
} />
</div>
<div className='form-row'>
<Controller name="ideals" control={control} render={({ field }) => <CheckboxGroup
control={control}
label="ideals"
options={ideals}
{...field}
/>
} />
</div>
</div>
<button
type='submit'
className='btn btn-block btn-danger'
>
Submit
</button>
</form>
</ThemeProvider>
)
};
note that the console.log statements show that the data are fully populated, for example:
and yet the form renders as if this data is blank (i.e., not undefined but with its initialised default values).
The onSubmit
is actually in the parent component, and is rather simple:
const onSubmit = async (
data: Partial<Char>
) => {
if (charstate.char) {
await dispatch(editChar(data));
} else {
// its a new char, so create
await dispatch(createChar(data));
}
};
and it works, in other words, I can fill the form out, and the form is submitted and saved to the datastore.
I have tried a variety of ways to either have the form wait until the values are populated, or try to force the controls to read the values (depending on whether this is an async issue or referencing issue). It feels like i'm missing something simple.
what am i missing?
Please try
const { handleSubmit, control } = useForm(values: data);
The values props will react to changes and update the form values, which is useful when your form needs to be updated by external state or server data.