具有相关选择值的 MUI 选择值超出范围

问题描述 投票:0回答:1

我目前遇到了这个问题,我有一个选择字段依赖于另一个字段。

MUI: You have provided an out-of-range value `1` for the select component.
Consider providing a value that matches one of the available options or ''.

这是我的两个领域

<Select
    labelId="originEntityLabel"
    id="originEntityField"
    displayEmpty
    defaultValue={entityForm.originEntity?.name ?? ""}
    label="Entity"
    onChange={(event: SelectChangeEvent) =>  onFieldChangeEntity(event.target.value, "entity")}                            
>
    <MenuItem key="none" value="">
        --None--
    </MenuItem>
    {entityList.map((entity) => {
        return (
            <MenuItem key={entity.name} value={entity.name}>
                {entity.name}
            </MenuItem>
        )
    })}
</Select>

这是我遇到问题的“选择”字段。

<Select
    labelId="startTierFieldLabel"
    id="startTierField"
    defaultValue={String(entityForm.startTier) ?? ""}
    label="Start Tier"
    onChange={(event: SelectChangeEvent) =>  onFieldChange(event.target.value, "tier")}                            
>
    {tierRange && tierRange.map((tier) => {
        return (
            <MenuItem key={tier} value={tier}>
                Tier {tier}
            </MenuItem>
        )
    })}
</Select>

tierRange 通过状态控制

 const [tierRange, setTierRange] = useState<number[]>(range(0, 11));

这是我的两个关于改变的方法

const onFieldChange = (value: any, field: string) => {
    const currEntity = entityForm as Entity;
    currEntity[field as keyof Entity] = value as never;
    console.log('field change', currEntity);
    setEntityForm(currEntity);
}

const onFieldChangeEntity = (value: any, field: string) => {
    console.log('field change entity', value);
    const entityLookup = entityList.find(entity => entity.name === value);
    const currEntity = entityForm as Entity;
    const minTier = entityLookup ? entityLookup.startTier + 1 : 0;
    currEntity.originEntity = entityLookup;
    currEntity.startTier = Math.max(currEntity.startTier, minTier);
    
    setEntityForm(cloneDeep(currEntity));
    setTierRange(range(minTier, 11));
}

我不确定为什么会出现这个错误。当我尝试记录信息时,currEntity 具有正确的 startTier,但我不确定为什么它在表单中没有正确反映。

enter image description here

我还尝试在entityForm状态上创建一个完全独立的useEffect,然后更新tierRange

useEffect(() => {
    console.log('in use effect entity form');
    const minTier = entityForm.originEntity ? entityForm.originEntity.startTier + 1 : 0;
    setTierRange(range(minTier, 11));
}, [entityForm]);

但这也无济于事。我对 typescript 和 mui 比较陌生,所以我不确定是什么原因造成的。 (另外,我愿意采用一种更好的方法来完成我正在尝试的事情 - 基本上让 1 个字段具有另一个字段的依赖值,如果知道的话也很好。)

typescript next.js select material-ui
1个回答
0
投票

TL; DR:使用第二个

value
<Select>
属性将其作为 受控 输入,并在其选项更改时重置它(至少当其当前
value
不再是一部分时)其新选项)。

  1. 第二个
    <Select>
    label="Start Tier"
    )有一些
    value
    (最初来自其
    defaultValue
    ,或其第一个选项值来自
    tierRange
  2. 您的用户在第一个
    <Select>
    (
    label="Entity"
    ) 中选择某个选项,触发其
    onChange
    回调,此处为
    onFieldChangeEntity
    ,这会更改第二个选择的
    tierRange
    选项以及
    entityForm.startTier
  3. 但是,后者仅用于设置第二个选择的
    defaultValue
    属性,因此它仅在最初影响其
    value
  4. 如果第二个选择的当前
    value
    不再是其选项的一部分,您会收到超出范围的错误

在步骤 2 中,您需要在更改第二个选择的 tierRange 选项的同时重置

(不仅仅是默认值),因此它必须是一个 受控 输入元素。至少如果它的当前值不再是新选项的一部分(但您可以选择在所有情况下重置它):

// value of 2nd Select (start tier)
const [selectedTier, setSelectedTier] = useState(String(entityForm.startTier) ?? tierRange[0]);

// onChange callback of the 2nd Select
const onFieldChange = (value: any, field: string) => {
  // etc.
  setSelectedTier(value); // We now have to explicitly control the Select value
}

// onChange callback of 1st Select (entity)
const onFieldChangeEntity = (value: any, field: string) => {
  // etc.
  const newTierRange = range(minTier, 11);
  setTierRange(newTierRange);

  // Reset the value of the 2nd Select (start tier),
  // at least if its current value is no longer in tierRange
  if (!newTierRange.includes(selectedTier)) {
    setSelectedTier(minTier); // or currEntity.startTier
  }
}

<Select
  value={selectedTier} // Use the Select value prop to turn it into a controlled input
  label="Start Tier"
  onChange={(event: SelectChangeEvent) => onFieldChange(event.target.value, "tier")}
>
  {/* tierRange options */}
</Select>
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.