为什么自定义输入组件会导致"无法为函数组件提供 refs"警告?



input尝试通过 MUI 的InputUnstyled组件(或任何其他非样式组件,例如SwitchUnstyledSelectUnstyled等),我收到警告

Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
Check the render method of `ForwardRef`.
InputElement@http://localhost:3000/main.4c2d885b9953394bb5ec.hot-update.js:59:45
div
...

我使用componentsprop 在我自己的MyStyledInput组件中定义一个自定义Input元素,该元素包装 MUIInputUnstyled

import InputUnstyled, {
InputUnstyledProps
} from '@mui/base/InputUnstyled';
const MyStyledInput: React.FC<InputUnstyledProps> = props => {
const { components, ...otherProps } = props;
return (
<InputUnstyled
components={{
Input: InputElement,
...components,
}}
{...otherProps}
/>
);
};

我的自定义input组件InputElement导致Function components cannot be given refs警告:

import {
InputUnstyledInputSlotProps,
} from '@mui/base/InputUnstyled';
import { Box, BoxProps } from '@mui/material';
const InputElement: React.FC<BoxProps & InputUnstyledInputSlotProps> = (
{ ownerState, ...props }
) => {
return (
<Box
component="input"
// any style customizations
{...props}
ref={ref}
/>
);
});

注意:我正在使用component="input使 MUI 的Box组件不是呈现 HTMLdiv而是呈现 DOM 中的 HTMLinput组件。

为什么我会收到此警告?

此处、此处和此处的其他相关问题解决了类似的问题,但不适用于 MUI 无样式组件。这些线程也没有解释为什么

警告要求您查看InputElement组件。老实说,堆栈跟踪在这里有点误导。它说:

检查ForwardRef的渲染方法。 InputElement@http://localhost:3000/main.4c2d885b9953394bb5ec.hot-update.js:59:45 迪夫

您可以忽略此处的ForwardRef。内部InputElement

理解此警告的关键部分是:

不能为函数组件提供引用。尝试访问此引用将失败。

也就是说,如果有人尝试通过ref访问 DOM 中的实际 HTMLinput元素(Material UI 实际上尝试这样做),它将不会成功,因为功能组件InputElement无法将该ref传递给input元素(此处通过 MUIBox组件创建)。

因此,警告继续显示:

你的意思是使用 React.forwardRef() 吗?

这提出了用React.forwardRef包装函数组件的解决方案。forwardRef使您可以掌握ref并将其传递给实际的input组件(在本例中是带有道具component="input"Box组件)。它应该看起来像这样:

import {
InputUnstyledInputSlotProps,
} from '@mui/base/InputUnstyled';
import { Box, BoxProps } from '@mui/material';
const InputElement = React.forwardRef<
HTMLInputElement,
BoxProps & InputUnstyledInputSlotProps
>(({ ownerState, ...props }, ref) => {
const theme = useTheme();
return (
<Box
component="input"
// any style customizations
{...props}
ref={ref}
/>
);
});

为什么我首先要处理ref

如果是 HTMLinput元素,您很有可能希望通过ref访问它的 DOM 节点。如果您将 Reactinput组件用作不受控制的组件,则会出现这种情况。不受控制的输入组件将其状态(即用户在该输入字段中输入的任何内容)保存在实际的 DOM 节点中,而不是在React.useState钩子的状态值内。如果通过React.useState挂钩控制输入值,则将输入用作受控组件。

: 具有type="file"的输入始终是不受控制的组件。这在 React 文档部分关于文件输入标签的解释。

最新更新