82877


React 17, React Hook Form v7, yup, Semantic-uiという環境にてReact学習中です。

共通コンポーネントを作成した際、以下のワーニングがコンソールに出力されました。

[code]

    index.js:1 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 `Controller`.
        at EmailField (http://localhost:3000/static/js/main.chunk.js:947:5)
        at Controller (http://localhost:3000/static/js/vendors~main.chunk.js:50587:35)
        at RhfEmailField (http://localhost:3000/static/js/main.chunk.js:2229:15)
        at form
        at Form (http://localhost:3000/static/js/vendors~main.chunk.js:62341:29)
        at App (http://localhost:3000/static/js/main.chunk.js:3737:70)
        at Outlet (http://localhost:3000/static/js/vendors~main.chunk.js:54276:10)
        at main
        at AppLayout
        at Routes (http://localhost:3000/static/js/vendors~main.chunk.js:54329:5)
        at div
        at App (http://localhost:3000/static/js/main.chunk.js:132:71)
        at Router (http://localhost:3000/static/js/vendors~main.chunk.js:54301:5)
        at BrowserRouter (http://localhost:3000/static/js/vendors~main.chunk.js:53799:5)
    
[/code]

おそらく、作成したコンポーネントでrefを指定していないためだと思っております。  
refについての理解が弱いところが原因と思います。どのように対応してよいかアドバイスいただけないでしょうか？

入力チェックは行われますが、コンソールのワーニングが消せるのであれば消したいです。

よろしくお願いします。

package.json

[code]

    {
      "name": "sfp-symphony",
      "version": "0.1.0",
      "private": true,
      "dependencies": {
        "@hookform/resolvers": "^2.8.1",
        "@reduxjs/toolkit": "^1.6.1",
        "@testing-library/jest-dom": "^5.11.10",
        "@testing-library/react": "^11.2.6",
        "@testing-library/user-event": "^13.1.1",
        "@types/jest": "^26.0.22",
        "@types/node": "^14.14.37",
        "@types/react": "^17.0.3",
        "@types/react-dom": "^17.0.3",
        "history": "^5.0.0",
        "lodash": "^4.17.21",
        "node-sass": "5.0.0",
        "react": "^17.0.2",
        "react-dom": "^17.0.2",
        "react-error-boundary": "^3.1.3",
        "react-helmet": "^6.1.0",
        "react-hook-form": "^7.16.1",
        "react-query": "^3.23.2",
        "react-router": "^6.0.0-beta.4",
        "react-router-dom": "^6.0.0-beta.4",
        "react-scripts": "4.0.3",
        "semantic-ui-css": "^2.4.1",
        "semantic-ui-react": "^2.0.3",
        "typescript": "^4.2.3",
        "web-vitals": "^1.1.1",
        "yup": "^0.32.9"
      },
      "scripts": {
        "start": "react-scripts start",
        "build": "react-scripts build",
        "test": "react-scripts test",
        "eject": "react-scripts eject",
        "fix": "npm run -s format && npm run -s lint:fix",
        "format": "prettier --write --loglevel=warn '{public,src}/**/*.{js,jsx,ts,tsx,html,gql,graphql,json}'",
        "lint": "npm run -s lint:style; npm run -s lint:es",
        "lint:fix": "npm run -s lint:style:fix && npm run -s lint:es:fix",
        "lint:es": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
        "lint:es:fix": "eslint --fix 'src/**/*.{js,jsx,ts,tsx}'",
        "lint:conflict": "eslint-config-prettier 'src/**/*.{js,jsx,ts,tsx}'",
        "lint:style": "stylelint 'src/**/*.{css,less,sass,scss}'",
        "lint:style:fix": "stylelint --fix 'src/**/*.{css,less,sass,scss}'",
        "preinstall": "typesync || :",
        "prepare": "simple-git-hooks > /dev/null"
      },
      "eslintConfig": {
        "extends": [
          "react-app",
          "react-app/jest"
        ]
      },
      "browserslist": {
        "production": [
          ">0.2%",
          "not dead",
          "not op_mini all"
        ],
        "development": [
          "last 1 chrome version",
          "last 1 firefox version",
          "last 1 safari version"
        ]
      },
      "devDependencies": {
        "@types/lodash": "^4.14.173",
        "@types/node-sass": "4.11.2",
        "@types/prettier": "^2.2.3",
        "@types/react-helmet": "^6.1.0",
        "@types/stylelint": "^9.10.1",
        "@types/testing-library__jest-dom": "^5.9.5",
        "@types/testing-library__user-event": "^4.2.0",
        "@types/yup": "^0.29.13",
        "@typescript-eslint/eslint-plugin": "^4.20.0",
        "@typescript-eslint/parser": "^4.20.0",
        "eslint-config-airbnb": "18.2.1",
        "eslint-config-prettier": "^8.1.0",
        "eslint-plugin-import": "^2.22.1",
        "eslint-plugin-jsx-a11y": "^6.4.1",
        "eslint-plugin-prefer-arrow": "^1.2.3",
        "eslint-plugin-react": "^7.23.1",
        "eslint-plugin-react-hooks": "4.2.0",
        "lint-staged": "^10.5.4",
        "prettier": "^2.2.1",
        "simple-git-hooks": "^2.3.1",
        "stylelint": "^13.12.0",
        "stylelint-config-recess-order": "^2.3.0",
        "stylelint-config-standard": "^21.0.0",
        "stylelint-order": "^4.1.0",
        "typesync": "^0.8.0"
      },
      "simple-git-hooks": {
        "pre-commit": ". ./lint-staged-around",
        "pre-push": ". ./test-around"
      },
      "lint-staged": {
        "src/**/*.{js,jsx,ts,tsx}": [
          "prettier --write --loglevel=error",
          "eslint --fix --quiet"
        ],
        "src/**/*.{css,less,sass,scss}": [
          "stylelint --fix --quiet"
        ],
        "{public,src}/**/*.{html,gql,graphql,json}": [
          "prettier --write --loglevel=error"
        ]
      }
    }
    
[/code]

App.tsx

[code]

    import { VFC } from 'react';
    import { Button, Form } from 'semantic-ui-react';
    import { YupJa as yup } from 'utils/validations/yup/i18n/YupJa';
    import { yupResolver } from '@hookform/resolvers/yup';
    import { SubmitHandler, useForm } from 'react-hook-form';
    import { RhfEmailField } from 'components/organisms/elements';
    
    type FormValues = {
      email: string;
      email2: string;
    };
    
    const schema = yup.object({
      email: yup.string().required().email().label('メールアドレス'),
      email2: yup.string().required().email().label('メールアドレス'),
    });
    
    const App: VFC = () => {
      const { control, handleSubmit } = useForm<FormValues>({
        resolver: yupResolver(schema),
      });
    
      const handleLogin: SubmitHandler<FormValues> = (data) => {
        console.log(data);
      };
    
      return (
        <Form size="large" onSubmit={handleSubmit(handleLogin)}>
          <RhfEmailField
            id="email"
            name="email"
            placeholder="メールアドレス"
            label="メールアドレス"
            required
            showIcon
            control={control}
          />
    
          <Button color="teal" fluid size="large">
            Click
          </Button>
        </Form>
      );
    };
    export default App;
    
[/code]

RhfEmailField.tsx

[code]

    /* eslint-disable react/destructuring-assignment,
                      @typescript-eslint/no-unsafe-assignment,
                      @typescript-eslint/no-unsafe-member-access,
                      @typescript-eslint/restrict-template-expressions
    */
    import { VFC } from 'react';
    import EmailField from 'components/molecules/elements/EmailField';
    import { Controller, DeepMap, FieldError, FieldValues } from 'react-hook-form';
    import { FormInputProps } from 'semantic-ui-react';
    import { InputFieldProps } from 'components/molecules/elements/ElementProps';
    
    export type RhfEmailFieldProps = InputFieldProps & FormInputProps;
    
    export const RhfEmailField: VFC<RhfEmailFieldProps> = (props) => (
      <Controller
        name={props.name}
        control={props.control}
        defaultValue=""
        render={({ field, formState: { errors } }) => (
          <EmailField
            label={props.label}
            id={props.id}
            placeholder={props.placeholder}
            isRequired={props.required}
            showIcon={props.showIcon}
            {...field}
            errorMessage={
              errors[props.name] &&
              `${(errors[props.name] as DeepMap<FieldValues, FieldError>)?.message}`
            }
          />
        )}
      />
    );
    
    export default RhfEmailField;
    
[/code]

EmailField.tsx

[code]

    import { VFC } from 'react';
    import ErrorMessage from 'components/atoms/elements/ErrorMessage';
    import { Form, Input } from 'semantic-ui-react';
    import { InputFieldProps, RhfRegisterInputFieldProps } from './ElementProps';
    
    type EmailFieldProps = InputFieldProps & RhfRegisterInputFieldProps;
    
    const EmailField: VFC<EmailFieldProps> = (props: EmailFieldProps) => {
      const {
        label,
        id,
        placeholder,
        isRequired,
        showIcon,
        errorMessage,
        value,
        onChange,
        onBlur,
      } = props;
      const icon: string = showIcon ? 'mail' : '';
      const iconPosition: 'left' | undefined = showIcon ? 'left' : undefined;
    
      return (
        <Form.Field required={isRequired}>
          <label>{label}</label>
          <Input
            type="email"
            id={id}
            placeholder={placeholder}
            icon={icon}
            iconPosition={iconPosition}
            error={!!errorMessage}
            value={value}
            onChange={onChange}
            onBlur={onBlur}
          />
          <ErrorMessage message={errorMessage} />
        </Form.Field>
      );
    };
    
    export default EmailField;
    
[/code]

ElementProps.tsx

[code]

    import { ChangeEventHandler, FocusEventHandler } from 'react';
    import { RefCallBack } from 'react-hook-form';
    
    export type InputFieldProps = {
      label?: string;
      id?: string;
      placeholder?: string;
      isRequired?: boolean;
      showIcon?: boolean;
      errorMessage?: string | undefined;
    };
    
    export type RhfRegisterInputFieldProps = {
      inputRef?: RefCallBack;
      value: string;
      onChange: ChangeEventHandler<HTMLInputElement>;
      onBlur: FocusEventHandler<HTMLInputElement>;
    };
    
[/code]


CC BY-SA 4.0
2021-10-03T12:39:27.197
82846
2021-10-05T01:59:02.330
2021-10-05T01:59:02.330
3060
48284
question
reactjs
コンソールに表示されたワーニングを削除するにはどうすればよいでしょうか？


`field` が展開されて `EmailField` の `ref` プロパティが設定されてしまっているのが原因でしょう。

[code]

    export const RhfEmailField: VFC<RhfEmailFieldProps> = (props) => (
      <Controller
        // ...
        render={({ field, formState: { errors } }) => (
          <EmailField
            // ...
            {...field} // ref={ref} 相当
            // ...
          />
        )}
      />
    
[/code]

[リファレンスのサンプルコード](https://react-hook-
form.com/api/usecontroller/controller)通りに書けば良いかと思います。

[code]

    export const RhfEmailField: VFC<RhfEmailFieldProps> = (props) => (
      <Controller
        // ...
        render={({ field: { onChange, onBlur, value, ref }, formState: { errors } }) => (
          <EmailField
            // ...
            onChange={onChange}
            onBlur={onBlur}
            value={value}
            inputRef={ref} // ref でなく inputRef
            // ...
          />
        )}
      />
    
[/code]


CC BY-SA 4.0
2021-10-05T01:57:39.963
82877
2021-10-05T01:57:39.963
2808
82846
answer