【问题标题】:ForwardRef warning React-hook-forms with Material UI TextFieldForwardRef 警告 React-hook-forms with Material UI TextField
【发布时间】:2021-02-23 10:54:39
【问题描述】:

我正在尝试使用带有 Material UI 输入的 react-hook-forms 构建一个表单(在这种情况下,我是 TextField 的自定义变体)。尽管表单似乎工作得很好,但在呈现表单时会在控制台中触发警告消息。

警告:函数组件不能被赋予 refs。尝试去 访问此 ref 将失败。你的意思是使用 React.forwardRef() 吗?

我正在使用 react-hook-form 的控制器来包装我的 TextField(按照文档的建议)

非常欢迎任何建议或解决方案!

在 TextField 组件和出现此问题的表单下方:

组件文本字段

const TextField = props => {
    const {
        icon,
        disabled,
        errors,
        helperText,
        id,
        label,
        value,
        name,
        required,
        ...rest
      } = props;

    const classes = useFieldStyles();
    
    return (
        <MuiTextField 
            {...rest}
            name={name}
            label={label}
            value={value || ''}
            required={required}
            disabled={disabled}
            helperText={helperText}
            error={errors}
            variant="outlined" 
            margin="normal" 
            color="primary"
            InputProps={{
                startAdornment: icon,
                classes: {
                    notchedOutline: classes.outline,
                },
            }}
            InputLabelProps={{
                className: classes.inputLabel,
            }}
        />
    )
};

TextField.propTypes = {
    icon: PropTypes.node,
    disabled: PropTypes.bool,
    label: PropTypes.string,
    id: PropTypes.string,
    value: PropTypes.any,
    required: PropTypes.bool,
    helperText: PropTypes.string,
};

export default TextField;

组件登录表单

const LoginForm = () => {
    const { handleSubmit, errors, control } = useForm();
    const onSubmit = values => console.log(values);

    return (
        <form onSubmit={handleSubmit(onSubmit)}>
            <Typography variant="h5" color="primary" gutterBottom>
                Login
            </Typography>

            <Box py={3} height="100%" display="flex" flexDirection="column">
                <Controller
                    as={TextField}
                    label="Username"
                    name="username"
                    control={control}
                    errors={errors}
                    required
                />

                <Controller
                    as={TextField}
                    label="Password"
                    type="password"
                    name="password"
                    control={control}
                    errors={errors}
                    required
                />

                <Link>
                    Forgot your password?
                </Link>
            </Box>

            <Button variant="contained" color="primary" fullWidth type="submit">
                Submit
            </Button>
        </form>
    )
};

【问题讨论】:

    标签: reactjs material-ui react-hook-form


    【解决方案1】:

    尝试使用Controller的render prop而不是as,因为TextField的暴露引用实际上称为inputRef,而Controller试图访问ref

    import React, { useState } from "react";
    import ReactDOM from "react-dom";
    import { useForm, Controller } from "react-hook-form";
    import Header from "./Header";
    import { TextField, ThemeProvider, createMuiTheme } from "@material-ui/core";
    import "react-datepicker/dist/react-datepicker.css";
    
    import "./styles.css";
    import ButtonsResult from "./ButtonsResult";
    
    let renderCount = 0;
    
    const theme = createMuiTheme({
      palette: {
        type: "dark"
      }
    });
    
    const defaultValues = {
      TextField: "",
      TextField1: ""
    };
    
    function App() {
      const { handleSubmit, reset, control } = useForm({ defaultValues });
      const [data, setData] = useState(null);
      renderCount++;
    
      return (
        <ThemeProvider theme={theme}>
          <form onSubmit={handleSubmit((data) => setData(data))} className="form">
            <Header renderCount={renderCount} />
            <section>
              <label>MUI TextField</label>
              <Controller
                render={(props) => (
                  <TextField
                    value={props.value}
                    onChange={props.onChange}
                    inputRef={props.ref}
                  />
                )}
                name="TextField"
                control={control}
                rules={{ required: true }}
              />
            </section>
    
            <section>
              <label>MUI TextField</label>
              <Controller
                render={(props) => (
                  <TextField
                    value={props.value}
                    onChange={props.onChange}
                    inputRef={props.ref}
                  />
                )}
                name="TextField1"
                control={control}
                rules={{ required: true }}
              />
            </section>
    
            <ButtonsResult {...{ data, reset, defaultValues }} />
          </form>
        </ThemeProvider>
      );
    }
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);
    
    

    您可以点击以下链接查看实际行为,现在通过控制器正确分配 ref,我们可以在出现错误时成功聚焦该字段以获得更好的可访问性。

    https://codesandbox.io/s/react-hook-form-focus-74ecu

    【讨论】:

    • 谢谢比尔,我后来也采用了这种方法,这确实可以防止 Ref.我还发现以前版本的 react-hook-form (v 6.0.8) 在使用 'as' 道具时没有这种行为
    • 是的,没错。我们在 6.10.0 中引入了额外的 ref 属性以改进焦点管理。 github.com/react-hook-form/react-hook-form/blob/master/…
    【解决方案2】:

    警告完全正确,正如官方文档所建议的那样,它认为您没有触及功能组件部分。 Link to the offical docs

    您不能将 ref 赋予功能组件,因为它们没有实例

    如果你想让人们对你的函数组件进行引用,你可以使用forwardRef(可能与useImperativeHandle一起使用),或者你可以将组件转换为一个类。

    但是,只要您像这样引用 DOM 元素或类组件,您就可以在函数组件中使用 ref 属性:

    function CustomTextInput(props) {
      // textInput must be declared here so the ref can refer to it
      const textInput = useRef(null);
      
      function handleClick() {
        textInput.current.focus();
      }
    
      return (
        <div>
          <input
            type="text"
            ref={textInput} />
          <input
            type="button"
            value="Focus the text input"
            onClick={handleClick}
          />
        </div>
      );
    }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-10
      • 1970-01-01
      • 2023-03-10
      • 1970-01-01
      • 2022-01-04
      • 2022-06-13
      • 1970-01-01
      • 2018-08-01
      相关资源
      最近更新 更多