提交时表单抛出错误的受控输入



我一直在尝试使用具有受控输入的表单提交登录请求。submit函数向下传递 React 组件,以便在 material-uiButtononClick时触发。仅当我使用 Apollo 客户端发送突变请求时,才会引发此错误。

index.js:1375 Warning: A component is changing an uncontrolled input of type text to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.

根据我对 React 文档中受控组件的理解,input组件通过使用 ReactvaluesetValue状态钩子来"控制"valueonChange属性。

这是包含submit函数和useMutation钩子的顶级Login组件。submit首先传递到LoginForm组件。

const Login = () => {
const [login, { data }] = useMutation(LOGIN);
console.log(data);
const submit = async form => {
console.log(form); // form object looks correct
await login({ variables: form });
};
...
<Container>
<LoginForm submit={submit} />
</Container>

这是呈现GeneralForm组件的LoginForm组件。同样,submit被传给GeneralForm.

const fields = [
{
id: "username",
label: "Username",
required: true,
placeholder: "example: 98sean98"
},
...
const LoginForm = props => {
const { submit } = props;
...
<Container>
<GeneralForm fields={fields} submit={submit} />
</Container>

这是GeneralForm组件。

const GeneralForm = props => {
const { fields, submit } = props;
const [form, setForm] = useState({});
useEffect(() => {
fields.forEach(field => {
form[field.id] = "";
});
setForm(form);
}, [form, fields]);
const handleChange = event => {
form[event.target.id] = event.target.value;
setForm(setForm);
};
const handleSubmit = () => {
if (validateForm(form)) { // returns a boolean indicating validity
submit(form); // trigger the submit function that is passed down from <Login />
} else {
alert("invalid form");
}
};
return (
<FormGroup>
{fields.map(field => (
<FormControl key={field.id} required={field.required}>
<InputLabel htmlFor={field.id}>{field.label}</InputLabel>
<Input
required={field.required}
id={field.id}
type={field.type ? field.type : "text"}
aria-describedby={
field.helperText ? `${field.id}-helper-text` : null
}
placeholder={field.placeholder}
value={form[field.id]}
onChange={handleChange}
/>
{field.helperText ? (
<FormHelperText id={`${field.id}-helper-text`}>
{field.helperText}
</FormHelperText>
) : null}
</FormControl>
))}
<Button type="submit" onClick={handleSubmit}>
Submit
</Button>
</FormGroup>
);
};

我的开发环境

partial packages list:
"@apollo/react-hooks": "^3.1.3",
"@material-ui/core": "^4.7.0",
"@material-ui/icons": "^4.5.1",
"apollo-boost": "^0.4.4",
"graphql": "^14.5.8",
"react": "^16.10.2",
"react-dom": "^16.10.2",
Machine: MacOS X Catalina 10.15.1

我现在观察到的特殊行为是,在不调用 Apollo 客户端突变请求的情况下,

const submit = async form => {
console.log(form);
// await login({ variables: form });
};

上述错误不会被触发。所以,我想知道阿波罗客户端是否以某种方式错误地更改了我的form对象。

我花了一些时间在互联网上挖掘,这个资源似乎很有帮助。显然,我所要做的就是将Inputvalue属性切换到侦听由同一组件中的 React 状态公开value,而不是从另一个组件传递form[field.id]

// GeneralForm.js
...
const [value, setValue] = useState(form[field.id] ? form[field.id] : "");
...
<Input value={value} ... />

因此,我将Input组件及其父FormControl模块化到另一个名为FormInput.js的文件中,并得出了这个解决方案。

// FormInput.js
const FormInput = props => {
const { field, form, setForm } = props;
const [value, setValue] = useState(form[field.id] ? form[field.id] : "");
const handleChange = event => {
setValue(event.target.value);
setForm({
...form,
[event.target.id]: event.target.value
});
};
return (
<FormControl key={field.id} required={field.required}>
<InputLabel htmlFor={field.id}>{field.label}</InputLabel>
<Input
required={field.required}
id={field.id}
type={field.type ? field.type : "text"}
aria-describedby={field.helperText ? `${field.id}-helper-text` : null}
placeholder={field.placeholder}
value={value}
onChange={handleChange}
/>
{field.helperText ? (
<FormHelperText id={`${field.id}-helper-text`}>
{field.helperText}
</FormHelperText>
) : null}
</FormControl>
);
};

然后,我将FormInput导入GeneralForm,传递所有必要的道具。

最新更新