Man*_*nos 4 javascript forms checkbox material-ui react-hook-form
我正在尝试构建一个包含多个“分组”复选框的表单,使用react-form-hook
Material UI
.
这些复选框是从 HTTP 请求异步创建的。
我想提供一组对象 ID 作为默认值:
defaultValues: { boat_ids: trip?.boats.map(boat => boat.id.toString()) || [] }
此外,当我选择或取消选择一个复选框时,我想将对象的ID添加/删除到react-hook-form
.
IE。( boat_ids: [25, 29, 4]
)
我怎样才能做到这一点?
这是我试图重现该问题的示例。
加分点,使用 Yup 验证最小选定复选框
boat_ids: Yup.array() .min(2, "")
Breaking API changes made in 6.X:
validationSchema
for tests). It feels as if they aren't sure what they want to do with the code there, and it is in a state of limbo. I would avoid their Controller entirely until it settles down, or use Controller as a thin wrapper for your own form Controller HOC, which appears to be the direction they want to go in."false"
value as a string of the Checkbox for referenceimport { yupResolver } from "@hookform/resolvers";
Run Code Online (Sandbox Code Playgroud)
const { register, handleSubmit, control, getValues, setValue } = useForm({
resolver: yupResolver(schema),
defaultValues: Object.fromEntries(
boats.map((boat, i) => [
`boat_ids[${i}]`,
preselectedBoats.some(p => p.id === boats[i].id)
])
)
});
Run Code Online (Sandbox Code Playgroud)
Controller
no longer handles Checkbox natively (type="checkbox"
), or to better put it, handles values incorrectly. It does not detect boolean values for checkboxes, and tries to cast it to a string value. You have a few choices:Controller
. Use uncontrolled inputsrender
prop to use a custom render function for your Checkbox and add a setValue hookExamples avoiding the use of Controller:
https://codesandbox.io/s/optimistic-paper-h39lq
https://codesandbox.io/s/silent-mountain-wdiov
Same as first original example but using yupResolver
wrapper
Description for 5.X:
Here is a simplified example that doesn't require Controller. Uncontrolled is the recommendation in the docs. It is still recommended that you give each input its own name
and transform/filter on the data to remove unchecked values, such as with yup and validatorSchema in the latter example, but for the purpose of your example, using the same name causes the values to be added to an array that fits your requirements.
https://codesandbox.io/s/practical-dijkstra-f1yox
Anyways, the problem is that your defaultValues
doesn't match the structure of your checkboxes. It should be {[name]: boolean}
, where names
as generated is the literal string boat_ids[${boat.id}]
, until it passes through the uncontrolled form inputs which bunch up the values into one array. eg: form_input1[0] form_input1[1]
emits form_input1 == [value1, value2]
https://codesandbox.io/s/determined-paper-qb0lf
构建defaultValues: { "boat_ids[0]": false, "boat_ids[1]": true ... }
控制器需要布尔值来切换复选框值,并将作为默认值提供给复选框。
const { register, handleSubmit, control, getValues, setValue } = useForm({
validationSchema: schema,
defaultValues: Object.fromEntries(
preselectedBoats.map(boat => [`boat_ids[${boat.id}]`, true])
)
});
Run Code Online (Sandbox Code Playgroud)
用于验证架构的架构,用于验证至少有 2 个选择,并将数据转换为所需的架构,然后再将其发送到 onSubmit。它过滤掉错误值,所以你得到一个字符串 id 数组:
const schema = Yup.object().shape({
boat_ids: Yup.array()
.transform(function(o, obj) {
return Object.keys(obj).filter(k => obj[k]);
})
.min(2, "")
});
Run Code Online (Sandbox Code Playgroud)
我也一直在努力解决这个问题,这对我有用。
更新了 react-hook-form v6 的解决方案,也可以不用useState
(下面的沙盒链接):
import React, { useState } from "react";
import { useForm, Controller } from "react-hook-form";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import Checkbox from "@material-ui/core/Checkbox";
export default function CheckboxesGroup() {
const defaultNames = ["bill", "Manos"];
const { control, handleSubmit } = useForm({
defaultValues: { names: defaultNames }
});
const [checkedValues, setCheckedValues] = useState(defaultNames);
function handleSelect(checkedName) {
const newNames = checkedValues?.includes(checkedName)
? checkedValues?.filter(name => name !== checkedName)
: [...(checkedValues ?? []), checkedName];
setCheckedValues(newNames);
return newNames;
}
return (
<form onSubmit={handleSubmit(data => console.log(data))}>
{["bill", "luo", "Manos", "user120242"].map(name => (
<FormControlLabel
control={
<Controller
name="names"
render={({ onChange: onCheckChange }) => {
return (
<Checkbox
checked={checkedValues.includes(name)}
onChange={() => onCheckChange(handleSelect(name))}
/>
);
}}
control={control}
/>
}
key={name}
label={name}
/>
))}
<button>Submit</button>
</form>
);
}
Run Code Online (Sandbox Code Playgroud)
Codesandbox 链接:https ://codesandbox.io/s/material-demo-54nvi ? file =/ demo.js
没有完成默认选定项目的另一种解决方案useState
:https :
//codesandbox.io/s/material-demo-bzj4i?file=/demo.js
归档时间: |
|
查看次数: |
9853 次 |
最近记录: |