2

我正在使用react-selectreact-final-form用于条件下拉菜单,其中第二个选择的选项由<PickOptions/>基于第一个选择的值的组件提供(感谢这个 SO answer)。

这是组件:

/** 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 || []);
};

当第一个选择的值更改时,它会清除第二个选择changeB(undefined)。我还通过传递将第二个选择设置为数组中的第一个选项initialValue。因为我需要从状态中初始化值,所以我最终得到了以下代码:

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]
}

但它不起作用。来自状态的初始值不会传递给由 呈现的字段<PickOptions/>。如果我从组件中删除changeB(undefined),则传递值,但是当第一个选择的值更改时(即使选项已更新),第二个选择的输入值不会更新。这是我的代码框的链接

我该如何解决?

4

2 回答 2

1

我能够通过获取该fields.map()部分映射的所有内容并将其包装在它自己的组件中以确保它们中的每一个具有单独的状态,从而使其工作。然后我只是将changeB(undefined)函数放在钩子的返回调用中,useEffect以在用户为第一个选择选择不同的选项后清除辅助选择,如下所示:

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

  return function cleanup() {
    changeB(undefined) // clear B
  };
}, [aValue, changeB, optionsMap]);

你可以在这个沙箱中看到它是如何工作的:React Final Form - Clear Secondary Selects

要更改辅助选择字段,您需要为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]);

这是该方法的沙箱:React Final Form - Update Secondary Selects

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

于 2019-11-15T19:42:10.467 回答
0

根据先前的答案,我最终在组件中使用了以下代码:

// 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]);

这样,它会检查用户是否更改了 aField,如果是,则将 bField 的值设置为数组中的第一个选项。

于 2019-11-17T14:09:07.920 回答