如何根据另一个 selection 在各种索引值处设置 Formik FieldArray select 选项

How to set Formik FieldArray select options at various index values based on another selection

我正在使用由以下字段组成的 Formik FieldArray:

Pet Type
Pet Food

我对这个 FieldArray 的 initialValues 设置如下:

const myPetGroup = {
      petDetails: [
        {
          petSelection: [
            {
              petType: "",
              petFood: ""
            }
          ]
        }
      ]
};

const INITIAL_FORM_STATE = {
  allPets: [myPetGroup]
}

基于 Pet Type 的 selection 值,我需要将一组特定的选项分配给 Pet Food。显然,我需要确保在每个行索引级别维护值。

假设我有以下选项 Pet Type

const petListOptions = [
  { value: "dog", label: "Dog" },
  { value: "cat", label: "Cat" }
];

以下是基于宠物的两种食物选择selection:

const dogFood = [
  { value: "dog food choice a", label: "Dog Food A" },
  { value: "dog food choice b", label: "Dog Food B" }
]; 

const catFood = [
  { value: "cat food a", label: "Cat Food A" },
  { value: "cat food b", label: "Cat Food B" }
];

假设我的 FieldArray 索引为 0:

<Select
  name={`petType.${index}`}
  options={petListOptions}
  value={dog}
/>

基于 Pet Type selection of dog 然后我如何设置以下 select 以在索引 0 处具有 dogFood 的选项,即:

<Select
  name={`petFood.${index}`}
  options={dogFood}
/>

现在如果用户在 FieldArray 中添加另一行,现在在索引 1 和现在 select cat,我如何设置选项现在在索引 1 使用 catFood

<Select
  name={`petType.${index}`}
  options={petListOptions}
  value={cat}
/>

<Select
  name={`petFood.${index}`}
  options={catFood}
/>

我不确定如何根据我的 FieldArray 中的宠物列表 selection 在各种索引处设置这些宠物食品选项。

因此,为了正确理解,您必须呈现一个控件列表,一个选择哪种类型的宠物,然后根据第一个选择,程序呈现可供选择的食物选项。

const petListOptions = [
  { value: "dog", label: "Dog" },
  { value: "cat", label: "Cat" }
];

从第一个列表中选择的值将决定接下来要呈现的选项。因此,为了便于检索,我保留了下面的 petFood 数组的键,以匹配从上面的第一个选择返回的一组可能值。

const petFood = {
  dog: [
    { value: "dog food choice a", label: "Dog Food A" },
    { value: "dog food choice b", label: "Dog Food B" }
  ],
  cat: [
    { value: "cat food a", label: "Cat Food A" },
    { value: "cat food b", label: "Cat Food B" }
  ]
};

为了保存 petType 和 petFood 的值,我们传递了一个数组,其中第一个对象已初始化,其中 petType 和 food 属性都设置为空。 这将只呈现一组行。

在下面的代码中:<Field name={petSelection.${index}.petType} as="select" value={selectedPet.petType}> ... </Field> 告诉 formik 如何存储选择的值。 注意 FieldArray 上的 name 属性。您要存储值的 属性 应该是 FieldArray's name <dot> Index。如果我们想将我们的值放在特定的 属性 中,我们可以将 <dot> Property name 附加到我们的 Select 字段的名称。

export const PetsList = () => (
  <div>
    <h1>Pet List</h1>
    <Formik
      initialValues={{
        petSelection: [
          {
            petType: "",
            petFood: ""
          }
        ]
      }}
      onSubmit={(values) =>
        setTimeout(() => {
          alert(JSON.stringify(values, null, 2));
        }, 500)
      }
      render={({ values }) => (
        <Form>
          <FieldArray
            name="petSelection"
            render={(arrayHelpers) => (
              <div>
                {values.petSelection && values.petSelection.length > 0 ? (
                  values.petSelection.map((selectedPet, index) => {
                    //console.log("selectedPet" + index, selectedPet);
                    return (
                      <div key={index}>
                        <Field
                          name={`petSelection.${index}.petType`}
                          as="select"
                          value={selectedPet.petType}
                        >
                          <option value="" disabled />
                          {petListOptions.map((pet, petIndex) => (
                            <option value={pet.value}>{pet.label}</option>
                          ))}
                        </Field>
                        {selectedPet.petType && (
                          <Field
                            name={`petSelection.${index}.petFood`}
                            as="select"
                            value={selectedPet.petFood}
                          >
                            <option value="" disabled />
                            {petFood[selectedPet.petType].map(
                              (food, foodIndex) => (
                                <option value={food.value}>{food.label}</option>
                              )
                            )}
                          </Field>
                        )}
                        <button
                          type="button"
                          onClick={() => arrayHelpers.remove(index)} // remove a friend from the list
                        >
                          -
                        </button>
                        <button
                          type="button"
                          onClick={() =>
                            arrayHelpers.insert(index, {
                              petType: "",
                              petFood: ""
                            })
                          } // insert an new object at a position
                        >
                          +
                        </button>
                      </div>
                    );
                  })
                ) : (
                  <button 
                      type="button" 
                      onClick={() => arrayHelpers.push({
                          petType: "",
                          petFood: ""
                      })}>
                    {/* show this when user has removed all pets from the list */}
                    Add a Pet
                  </button>
                )}
                <div>
                  <button type="submit">Submit</button>
                </div>
              </div>
            )}
          />
        </Form>
      )}
    />
  </div>
);

添加按钮只是将一个新对象添加到 petsSelection 数组,属性 petTypepetFood 初始化为空字符串。 现在,在您进行选择的任何行中,您一定要将值添加到这个新对象!