Race Condition: Material-UI Select 在执行条件渲染生成 MenuItem 时认为值超出范围
Race Condition: Material-UI Select thinks value is out of range when performing conditional rendering to generate MenuItems
我正在使用 Material-UI 为我的仪表板创建一些 Select。 Select 中的菜单项(选项)是使用条件渲染生成的。我根据从远程 API 检索的数组中的一组选项列表使用映射到 return MenuItems。 Select 的值也是根据从远程 API 检索到的值确定的。根据 API 响应,默认值更新为实际值。
快速浏览一下组件的相关部分:
<Select
MenuProps={{
className: classes.selectMenu,
}}
classes={{
select: classes.select,
}}
id={id}
name={name}
defaultValue={defaultValue}
value={value}
onChange={onChange}
>
<MenuItem
disabled
classes={{
root: classes.selectMenuItem,
}}
value={0}
>
{labelText}
</MenuItem>
{selectOptions.map(opt =>
<MenuItem
classes={{
root: classes.selectMenuItem,
selected: classes.selectMenuItemSelected,
}}
value={opt.IDX}
key={`${name}${opt.IDX}`}
>
{opt.Name}
</MenuItem>)}
</Select>
每个选项都有一个 IDX 属性 和一个名称 属性。因此,例如,下拉列表中的用户列表将显示 Bob、Sally、Jeff,并且相对于 Bob、Sally 和 Jeff 的 ID 号,值将是 1、2、3 等。如您所见,有一个指定值为 0 的默认选项和一个 defaultValue 属性。
我在 JS 控制台中收到以下警告:
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 ''.
The available values are `0`.
我只能假设是因为 React 直到渲染后才知道有条件渲染的 MenuItem,此时远程 API 可能已经响应并且值Select 组件已经设置为默认值以外的值。
这似乎不会以任何方式影响代码功能,但它是一种竞争条件,我不喜欢它。有没有一种方法可以执行检查以确保我的组件具有所有可用的 MenuItem 并在设置父 select 组件的值之前设置它们的值?
我正在考虑以某种方式在 JSX 中设置类似 isFullyProcessed 布尔值的东西,然后使用它。
编辑:
以下是我在父页面上获取数据的方式。时间表和组是选项数据,用户是价值的来源。
useEffect(() => {
axios.get(`${server}${uPath}/data`).then((response) => {
const parsed = JSON.parse(response.data);
setSchedules(parsed.schedules);
setGroups(parsed.groups);
setUser(parsed.user);
如评论所述,通过等待渲染直到从 API 检索到所有数据来解决此问题。显然,即使 API 调用设置值和设置菜单选项是在同一个函数中完成的,因为我使用两个独立的状态来存储此信息,所以可以在不同的渲染中设置值循环比呈现菜单选项。
我添加了一个 isLoading 布尔值并等待使用效果 return 来自 API 的数据,这解决了问题。 Quick tutorial here.
我正在使用 Material-UI 为我的仪表板创建一些 Select。 Select 中的菜单项(选项)是使用条件渲染生成的。我根据从远程 API 检索的数组中的一组选项列表使用映射到 return MenuItems。 Select 的值也是根据从远程 API 检索到的值确定的。根据 API 响应,默认值更新为实际值。
快速浏览一下组件的相关部分:
<Select
MenuProps={{
className: classes.selectMenu,
}}
classes={{
select: classes.select,
}}
id={id}
name={name}
defaultValue={defaultValue}
value={value}
onChange={onChange}
>
<MenuItem
disabled
classes={{
root: classes.selectMenuItem,
}}
value={0}
>
{labelText}
</MenuItem>
{selectOptions.map(opt =>
<MenuItem
classes={{
root: classes.selectMenuItem,
selected: classes.selectMenuItemSelected,
}}
value={opt.IDX}
key={`${name}${opt.IDX}`}
>
{opt.Name}
</MenuItem>)}
</Select>
每个选项都有一个 IDX 属性 和一个名称 属性。因此,例如,下拉列表中的用户列表将显示 Bob、Sally、Jeff,并且相对于 Bob、Sally 和 Jeff 的 ID 号,值将是 1、2、3 等。如您所见,有一个指定值为 0 的默认选项和一个 defaultValue 属性。
我在 JS 控制台中收到以下警告:
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 ''. The available values are `0`.
我只能假设是因为 React 直到渲染后才知道有条件渲染的 MenuItem,此时远程 API 可能已经响应并且值Select 组件已经设置为默认值以外的值。
这似乎不会以任何方式影响代码功能,但它是一种竞争条件,我不喜欢它。有没有一种方法可以执行检查以确保我的组件具有所有可用的 MenuItem 并在设置父 select 组件的值之前设置它们的值?
我正在考虑以某种方式在 JSX 中设置类似 isFullyProcessed 布尔值的东西,然后使用它。
编辑:
以下是我在父页面上获取数据的方式。时间表和组是选项数据,用户是价值的来源。
useEffect(() => {
axios.get(`${server}${uPath}/data`).then((response) => {
const parsed = JSON.parse(response.data);
setSchedules(parsed.schedules);
setGroups(parsed.groups);
setUser(parsed.user);
如评论所述,通过等待渲染直到从 API 检索到所有数据来解决此问题。显然,即使 API 调用设置值和设置菜单选项是在同一个函数中完成的,因为我使用两个独立的状态来存储此信息,所以可以在不同的渲染中设置值循环比呈现菜单选项。
我添加了一个 isLoading 布尔值并等待使用效果 return 来自 API 的数据,这解决了问题。 Quick tutorial here.