Reactjs 从状态初始化的react final form中带有react select的条件下拉列表

Reactjs 从状态初始化的react final form中带有react select的条件下拉列表,reactjs,react-select,react-final-form,react-final-form-arrays,Reactjs,React Select,React Final Form,React Final Form Arrays,我使用react select和react final form作为条件下拉列表,其中第二个选择的选项由组件根据第一个选择的值提供(由于如此) 以下是组件: /** Changes options and clears field B when field A changes */ const PickOptions = ({ a, b, optionsMap, children }) => { const aField = useField(a, { subscription: {

我使用
react select
react final form
作为条件下拉列表,其中第二个选择的选项由
组件根据第一个选择的值提供(由于如此)

以下是组件:

/** Changes options and clears field B when field A changes */
const PickOptions = ({ a, b, optionsMap, children }) => {
  const aField = useField(a, { subscription: { value: 1 } });
  const bField = useField(b, { subscription: {} });
  const aValue = aField.input.value.value;
  const changeB = bField.input.onChange;
  const [options, setOptions] = React.useState(optionsMap[aValue]);

  React.useEffect(() => {
    changeB(undefined); // clear B
    setOptions(optionsMap[aValue]);
  }, [aValue, changeB, optionsMap]);
  return children(options || []);
};
// subscibe to keep track of aField has been changed
const aFieldSubscription = useField(a, { subscription: { dirty: 1 } });

React.useEffect(() => {
  setOptions(optionsMap[aValue]);

  if (optionsMap[aValue]) {
    // set of bValues defined in array
    const bValueSet = optionsMap[aValue].filter(x => x.type === optionType);

    if (aFieldSubscription.meta.dirty) {
      changeB(bValueSet[0]); // change B
    }
  }
}, [aValue, changeB, optionsMap]);
当第一个选择的值更改为
changeB(未定义)
时,它将清除第二个选择。我还通过传递
initialValue
将第二个select设置为数组中的第一个选项。由于需要从状态中初始化值,因此我最终得到以下代码:

initialValue={
  this.state.data.options[index] &&
  this.state.data.options[index].secondOption
    ? this.state.data.options[index]
        .secondOption
    : options.filter(
        option => option.type === "option"
      )[0]
}
但它不起作用。状态的初始值不会传递到由
呈现的字段。如果我从组件中删除
changeB(未定义)
,则会传递值,但当第一次选择的值更改时(即使选项已更新),第二次选择的输入值不会更新。这是我的网站的链接


如何修复它?

我可以通过获取由
fields.map()
部分映射的所有内容,并将其包装到自己的组件中,以确保每个字段都有单独的状态,从而实现此功能。然后,我只是将
changeB(undefined)
函数放在
useffect
钩子的返回调用中,以便在用户为第一次选择选择不同的选项后清除辅助选择,如下所示:

React.useEffect(() => {
  setOptions(optionsMap[aValue]);

  return function cleanup() {
    changeB(undefined) // clear B
  };
}, [aValue, changeB, optionsMap]);
您可以在这个沙箱中看到它是如何工作的:

要更改辅助选择字段,您需要为数组对应的选项类型向
PickOptions
传递一个额外的道具。我还订阅并跟踪上一个
bValue
,以检查它是否存在于当前
bValueSet
数组中。如果它存在,我们就不去管它,否则我们用它对应的
optionType
数组中的第一个值来更新它

  // subscibe to keep track of previous bValue
  const bFieldSubscription = useField(b, { subscription: { value: 1 } })
  const bValue = bFieldSubscription.input.value.value

  React.useEffect(() => {
    setOptions(optionsMap[aValue]);

    if (optionsMap[aValue]) {
      // set of bValues defined in array
      const bValueSet = optionsMap[aValue].filter(x => x.type === optionType);

      // if the previous bValue does not exist in the current bValueSet then changeB
      if (!bValueSet.some(x => x.value === bValue)) {
        changeB(bValueSet[0]); // change B
      }
    }

  }, [aValue, changeB, optionsMap]);
下面是该方法的沙箱:


我还将您的类组件更改为函数式组件,因为我更容易查看和测试正在发生的事情,但这种方法也应该适用于您的类组件。

基于前面的答案,我在组件中使用了以下代码:

/** Changes options and clears field B when field A changes */
const PickOptions = ({ a, b, optionsMap, children }) => {
  const aField = useField(a, { subscription: { value: 1 } });
  const bField = useField(b, { subscription: {} });
  const aValue = aField.input.value.value;
  const changeB = bField.input.onChange;
  const [options, setOptions] = React.useState(optionsMap[aValue]);

  React.useEffect(() => {
    changeB(undefined); // clear B
    setOptions(optionsMap[aValue]);
  }, [aValue, changeB, optionsMap]);
  return children(options || []);
};
// subscibe to keep track of aField has been changed
const aFieldSubscription = useField(a, { subscription: { dirty: 1 } });

React.useEffect(() => {
  setOptions(optionsMap[aValue]);

  if (optionsMap[aValue]) {
    // set of bValues defined in array
    const bValueSet = optionsMap[aValue].filter(x => x.type === optionType);

    if (aFieldSubscription.meta.dirty) {
      changeB(bValueSet[0]); // change B
    }
  }
}, [aValue, changeB, optionsMap]);

通过这种方式,它会检查用户是否更改了“远场”,如果是,它会将“远场”的值设置为数组中的第一个选项。

非常感谢您的回复!我会试试看。但我还需要在更改第一个选择后,将第二个选择设置为数组中的第一个选项。仅当用户手动更改字段时,而不是从状态初始化表单时,才会发生这种情况。请参阅上面示例中的
initialValue
代码。@jupiteror我已修改了我的答案,以解决我认为您期望的结果。检查第二个沙盒链接。谢谢!但第二个示例中的值现在未初始化(这就是问题所在,我正在努力解决。@jupiteror很抱歉,我一定没有正确保存它,请再次尝试第二个示例。当您移动第一个选项时,值应该初始化并更改。现在还有两个问题。第一,当您尝试添加新选项时,应用程序崩溃。第二,第二个选项中的值始终为设置为数组中的第一个选项,而不是状态中的选项。第二个字段中的第二个选项应该是两个B,但它是两个A。