我一直在尝试使用具有受控输入的表单提交登录请求。submit
函数向下传递 React 组件,以便在 material-uiButton
onClick
时触发。仅当我使用 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
组件通过使用 Reactvalue
和setValue
状态钩子来"控制"value
和onChange
属性。
这是包含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
对象。
我花了一些时间在互联网上挖掘,这个资源似乎很有帮助。显然,我所要做的就是将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
,传递所有必要的道具。