表单中的受控输入在提交时抛出错误
Controlled input in form throwing error upon submission
我一直在尝试使用具有受控输入的表单提交登录请求。 submit
函数向下传递到 React 组件,在 material-ui Button
的 onClick
时触发。仅当我使用 Apollo Client 发送变更请求时才会抛出此错误。
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.
根据我对 controlled components in React's docs 的理解,input
组件是 "controlled" 通过在 value
中使用 React value
和 setValue
state hooks 和onChange
个属性。
这是顶级 Login
组件,包含 submit
函数和 useMutation
挂钩。 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>
这是 LoginForm
组件,它呈现 GeneralForm
组件。同样,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 Client 变更请求的情况下,
const submit = async form => {
console.log(form);
// await login({ variables: form });
};
不会触发上述错误。所以,我想知道 Apollo Client 是否以某种方式错误地更改了我的 form
对象。
我花了一些时间在 Internet 上搜索,这个 resource 似乎很有帮助。显然,我所要做的就是将 Input
的 value
属性切换为监听由 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
,传递所有必要的道具。
我一直在尝试使用具有受控输入的表单提交登录请求。 submit
函数向下传递到 React 组件,在 material-ui Button
的 onClick
时触发。仅当我使用 Apollo Client 发送变更请求时才会抛出此错误。
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.
根据我对 controlled components in React's docs 的理解,input
组件是 "controlled" 通过在 value
中使用 React value
和 setValue
state hooks 和onChange
个属性。
这是顶级 Login
组件,包含 submit
函数和 useMutation
挂钩。 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>
这是 LoginForm
组件,它呈现 GeneralForm
组件。同样,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 Client 变更请求的情况下,
const submit = async form => {
console.log(form);
// await login({ variables: form });
};
不会触发上述错误。所以,我想知道 Apollo Client 是否以某种方式错误地更改了我的 form
对象。
我花了一些时间在 Internet 上搜索,这个 resource 似乎很有帮助。显然,我所要做的就是将 Input
的 value
属性切换为监听由 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
,传递所有必要的道具。