繁体   English   中英

ForwardRef 警告 React-hook-forms with Material UI TextField

[英]ForwardRef warning React-hook-forms with Material UI TextField

我正在尝试使用带有 Material UI 输入的 react-hook-forms 构建一个表单(在这种情况下是我的 TextField 自定义变体)。 尽管表单看起来完全正常,但它在呈现表单时会在控制台中触发一条警告消息。

警告:不能为函数组件提供引用。 尝试访问此引用将失败。 你的意思是使用 React.forwardRef() 吗?

我正在使用 react-hook-form 的 Controller 来包装我的 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>
    )
};

尝试使用Controller的 render prop 而不是as ,因为 TextField 公开的 ref 实际上称为 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);

您可以单击以下链接查看实际行为,现在使用 Controller 正确分配了 ref,当出现错误时,我们可以成功地专注于该领域以获得更好的可访问性。

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

该警告完全正确,正如官方文档所建议的那样,它认为您没有触及功能组件部分。 链接到官方文档

您不能为功能组件提供 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>
  );
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM