感谢阅读。
我正在尝试使用Formik构建表单。并且它在FieldArray中包含一个FieldArray。
由于某种原因,setFieldValue可以正常运行,可以用console.log记录正确的e.target.name
和e.target.value
问题在于提交表单时,来自输入的所有值均未位于应有的位置。预期的行为是,值应位于exclusionGroups内部,而不是外部。
任何人都可以给我一些见识吗?我整天都被困在这里,感觉好像我的头会爆炸。
预期:
exclusionGroups: [
{
exclusion: [
{
param: 'delayMin',
operator: '<',
value: 'test1',
},
{
param: 'airlineCode',
operator: '>',
value: 'test2',
},
],
},
{
exclusion: [
{
param: 'flightNumber',
operator: '=',
value: 'test3',
},
],
},
],
现实:
exclusionGroups: (2) [{…}, {…}]
group-1-operator-1: "<"
group-1-operator-2: ">"
group-1-param-1: "delayMin"
group-1-param-2: "airlineCode"
group-1-value-1: "test1"
group-1-value-2: "test2"
group-2-operator-1: "="
group-2-param-1: "flightNumber"
group-2-value-1: "test3"
我的代码:
Index.tsx
type ExclusionRuleValues = {
param: string;
operator: string;
value: string;
};
interface ExclusionGroupProps {
exclusionRules?: ExclusionRuleValues[];
}
const Exclusion = ({ data, type }: any) => {
const onSubmit = (values: any) => {
console.log(values);
};
const initialValues = {
exclusionGroups: [
{
exclusion: [
{
param: 'group1',
operator: 'group1',
value: 'group1',
},
],
},
{
exclusion: [
{
param: 'group2',
operator: 'group2',
value: 'group2',
},
],
},
],
};
const emptyGroup = {
exclusion: [
{
param: '',
operator: '',
value: '',
},
],
};
return (
<React.Fragment>
<Formik
enableReinitialize
onSubmit={onSubmit}
initialValues={initialValues}
render={(formProps) => {
const { values, handleSubmit, submitForm } = formProps;
const { exclusionGroups } = values;
const setFieldValue = (e: ChangeEvent<HTMLInputElement>) => {
return formProps.setFieldValue(e.target.name, e.target.value);
};
return (
<React.Fragment>
<Header>
Model will return excluded message code if the following condition is true.
<Button onClick={submitForm} color="primary">
Save Changes
</Button>
</Header>
<Form onSubmit={handleSubmit}>
<FieldArray
name="exclusionGroups"
render={(arrayHelper) => (
<React.Fragment>
{exclusionGroups.map((exclusionRulesGroup: any, index: number) => {
return (
<TargetFields
type={type}
group={index + 1}
key={`field-${index}`}
name={`${arrayHelper.name}.${index}`}
setFieldValue={setFieldValue}
/>
);
})}
<AddNewGroupButton type="button" onClick={() => arrayHelper.push(emptyGroup)}>
+ New Group
</AddNewGroupButton>
</React.Fragment>
)}
/>
</Form>
</React.Fragment>
);
}}
/>{' '}
</React.Fragment>
);
};
export default Exclusion;
TargetFields.tsx
interface TargetFieldsProps {
group: number;
name: string;
type: string;
data?: ExclusionRuleValues[];
setFieldValue: (e: ChangeEvent<HTMLInputElement>) => void;
}
const TargetFields = ({ group, data, name, type, setFieldValue }: TargetFieldsProps) => {
const emptyTarget = {
param: '',
operator: '',
value: '',
};
return (
<React.Fragment>
<Field name={name}>
{(fieldProps: any) => (
<React.Fragment>
<ExclusionGroupHeader>
<b>Group {group}</b>
</ExclusionGroupHeader>
<Wrapper>
<FieldArray
name={`${fieldProps.field.name}.exclusion`}
key={`exclusion-${group}`}
render={(targetHelper) => (
<React.Fragment>
{fieldProps.field.value.exclusion.map(
(target: ExclusionRuleValues, key: number) => {
const { param, operator, value } = target;
return (
<ExclusionRuleGroup key={`group-${key}`}>
<ExclusionRuleHeader>
<b>Target {key + 1}</b>
<DeleteButton type="button" onClick={() => targetHelper.remove(key)}>
remove
</DeleteButton>
</ExclusionRuleHeader>
<StyledRow>
<CCol sm="4">
<Select
onChange={setFieldValue}
// value={param}
label="Params"
name={`group-${group}-param-${key + 1}`}
options={
type === 'input' ? InputExclusionParams : OutputExclusionParams
}
placeholder="Operator"
/>
</CCol>
<CCol sm="4">
<Select
onChange={setFieldValue}
// value={operator}
label="Operator"
name={`group-${group}-operator-${key + 1}`}
options={SelectOptions}
placeholder="Operator"
/>
</CCol>
<CCol sm="4">
<Input
onChange={setFieldValue}
// value={value}
label="Value"
name={`group-${group}-value-${key + 1}`}
type="text"
placeholder="Value"
/>
</CCol>
</StyledRow>
</ExclusionRuleGroup>
);
}
)}
<AddNewRuleButton type="button" onClick={() => targetHelper.push(emptyTarget)}>
+ New Rule
</AddNewRuleButton>
</React.Fragment>
)}
/>
</Wrapper>
</React.Fragment>
)}
</Field>
</React.Fragment>
);
};
export default TargetFields;
答案 0 :(得分:0)
问题是当您将name
属性传递给表单的输入时。
在组件TargetFields
中,您传递的名称类似name={`group-${group}-operator-${key + 1}`}
,因此formik认为您希望将该值存储在该字符串产生的属性中,例如group-1-operator-1
,这就是为什么要使用您想要的对象,而要使用具有该名称的属性的原因。
如果要使用嵌套的对象/数组,则需要使用.
或[${index}]
将名称与想要的对象连接起来,就像您在此处所做的那样
<TargetFields
type={type}
group={index + 1}
key={`field-${index}`}
name={`${arrayHelper.name}.${index}`} // You use the . with the name and the index.
setFieldValue={setFieldValue} // It could also be using [] instead of . like this => `${arrayHelper.name}[${index}]`
/>
就像这里
<FieldArray
name={`${fieldProps.field.name}.exclusion`} // You use the . with the name and the property of the object you want
key={`exclusion-${group}`}
render={(targetHelper) => ( ... )
/>
因此,要解决您的问题,您需要更改以下内容。
<StyledRow>
<CCol sm="4">
<Select
onChange={setFieldValue}
// value={param}
label="Params"
name={`${targetHelper}[${key}].param`}
options={
type === 'input' ? InputExclusionParams : OutputExclusionParams
}
placeholder="Operator"
/>
</CCol>
<CCol sm="4">
<Select
onChange={setFieldValue}
// value={operator}
label="Operator"
name={`${targetHelper}[${key}].operator`}
options={SelectOptions}
placeholder="Operator"
/>
</CCol>
<CCol sm="4">
<Input
onChange={setFieldValue}
// value={value}
label="Value"
name={`${targetHelper}[${key}].value`}
type="text"
placeholder="Value"
/>
</CCol>
</StyledRow>
只是一个猜测,您不是凭自己的能力编写了所有代码?因为在一个地方,您正在做解决您的问题所需的一切。如果您不知道该名称如何与FieldArray
一起使用,建议您阅读formik docs的这一部分。知道如何工作对于使用嵌套对象/数组非常重要。