Knower
Auth
Debugging
Functional Component's forwardRef

Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

What I tried to do

After creating signup form for registering new user, I created custom <Input /> component separately in which users can type their information for signing up. Then, I tried to use watch() (opens in a new tab) method in react-hook-form package to see what users wrote down for their inputs.


What I actually tried

Signup Form

src/app/create-account/page.tsx
Copy

"use client";
import "./style.CreateAccount.scss";
import { useMemo } from "react";
import { useForm } from "react-hook-form";
import Input from "@/components/input/Input";
import Button from "@/components/button/Button/Button";
import useYupResolver from "@/hooks/useYupResolver";
import { signUpValidationSchema } from "./createAccountValidationSchema";
interface SignupInput {
firstName: string;
lastName: string;
email: string;
password: string;
phoneNumber: string;
confirmPassword: string;
addressFirst?: string;
addressSecond?: string;
city?: string;
country?: string;
zipCode?: string;
}
export default function CreateAccount(): JSX.Element {
// ...
console.log(watch());
return (
<section>
<div className="title__wrapper">
<h1 className="title">create account</h1>
</div>
<div className="form__wrapper">
<form
id="create-account"
onSubmit={handleSubmit(signUpFormSubmit, invalidSignUpSubmit)}
>
<div className="input-container">
<div id="user-info">
<div className="inside">
<Input
type="text"
placeholder="first name"
{...register("firstName")}
/>
<Input
type="text"
placeholder="last name"
{...register("lastName")}
/>
</div>
<Input type="email" placeholder="e-mail" {...register("email")} />
<Input
type="text"
placeholder="phone number"
{...register("phoneNumber")}
/>
<Input
type="password"
placeholder="password"
{...register("password")}
/>
<Input
type="password"
placeholder="confirm password"
{...register("confirmPassword")}
/>
</div>
<hr />
<div id="address-info">
<Input
type="text"
placeholder="address 1"
{...register("addressFirst")}
/>
<Input
type="text"
placeholder="address 2"
{...register("addressSecond")}
/>
<Input type="text" placeholder="city" {...register("city")} />
<div className="inside">
<Input
type="text"
placeholder="country"
{...register("country")}
/>
<Input
type="text"
placeholder="zip code"
{...register("zipCode")}
/>
</div>
</div>
</div>
<div className="submit-button">
<Button text="submit" inverted={true} />
</div>
</form>
</div>
</section>
);
}

Input Component

src/components/input/Input.tsx
Copy

import React from "react";
import "./style.Input.scss";
interface InputProp extends React.InputHTMLAttributes<HTMLInputElement> {
error?: boolean;
}
function Input({ type, ...props }: InputProp): JSX.Element {
return <input type={type} placeholder={props.placeholder} />;
}
export default Input;

Error that I got

I got the following error in my browser console.


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 `CreateAccount`.
at Input (webpack-internal:///(app-pages-browser)/./src/components/input/Input.tsx:22:11)
at div
at div
at form
at div
at section
at CreateAccount (webpack-internal:///(app-pages-browser)/./src/app/create-account/page.tsx:25:76)
at InnerLayoutRouter (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/layout-router.js:229:11)
at RedirectErrorBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/redirect-boundary.js:73:9)
at RedirectBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/redirect-boundary.js:81:11)
at NotFoundBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/not-found-boundary.js:62:11)
at LoadingBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/layout-router.js:326:11)
at ErrorBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/error-boundary.js:110:11)
at InnerScrollAndFocusHandler (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/layout-router.js:139:9)
at ScrollAndFocusHandler (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/layout-router.js:215:11)
at RenderFromTemplateContext (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/render-from-template-context.js:15:44)
at OuterLayoutRouter (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/layout-router.js:336:11)
at InnerLayoutRouter (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/layout-router.js:229:11)
at RedirectErrorBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/redirect-boundary.js:73:9)
at RedirectBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/redirect-boundary.js:81:11)
at NotFoundErrorBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/not-found-boundary.js:54:9)
at NotFoundBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/not-found-boundary.js:62:11)
at LoadingBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/layout-router.js:326:11)
at ErrorBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/error-boundary.js:110:11)
at InnerScrollAndFocusHandler (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/layout-router.js:139:9)
at ScrollAndFocusHandler (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/layout-router.js:215:11)
at RenderFromTemplateContext (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/render-from-template-context.js:15:44)
at OuterLayoutRouter (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/layout-router.js:336:11)
at div
at body
at html
at RootLayout (webpack-internal:///(app-pages-browser)/./src/app/layout.tsx:21:11)
at RedirectErrorBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/redirect-boundary.js:73:9)
at RedirectBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/redirect-boundary.js:81:11)
at NotFoundErrorBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/not-found-boundary.js:54:9)
at NotFoundBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/not-found-boundary.js:62:11)
at DevRootNotFoundBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/dev-root-not-found-boundary.js:32:11)
at ReactDevOverlay (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/react-dev-overlay/internal/ReactDevOverlay.js:66:9)
at HotReload (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/react-dev-overlay/hot-reloader-client.js:326:11)
at Router (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/app-router.js:147:11)
at ErrorBoundaryHandler (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/error-boundary.js:82:9)
at ErrorBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/error-boundary.js:110:11)
at AppRouter (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/components/app-router.js:396:13)
at ServerRoot (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/app-index.js:123:11)
at RSCComponent
at Root (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@13.4.16_react-dom@18.2.0_react@18.2.0_sass@1.64.0/node_modules/next/dist/client/app-index.js:139:11)

forwardRef_error Referrence: bobbyhadz.com

Package version


"dependencies": {
"@prisma/client": "^5.1.1",
"@types/node": "20.4.2",
"@types/react": "18.2.15",
"@types/react-dom": "18.2.7",
"eslint": "8.45.0",
"eslint-config-next": "13.4.11",
"next": "^13.4.16",
"ra-data-json-server": "^4.13.0",
"react": "18.2.0",
"react-admin": "4.10",
"react-dom": "18.2.0",
"react-hook-form": "^7.45.4",
"typescript": "5.1.6",
"yup": "^1.2.0"
},

Solution

According to the answer in Stackoverflow (opens in a new tab), I need to wrap <Input /> component with forwardRef (opens in a new tab).

forwardRef lets child component expose DOM node to its parent component with ref (opens in a new tab). As functional component does not have instances unlike class component and JSX element1.

Therefore, I changed my <Input /> component as follows.

src/components/input/Input.tsx
Copy

import React, { FC, forwardRef } from "react";
import "./style.Input.scss";
interface InputProp extends React.InputHTMLAttributes<HTMLInputElement> {
error?: boolean;
}
const Input: FC<InputProp> = forwardRef<HTMLInputElement, InputProp>(
({ error, ...props }, ref) => {
return (
<input
ref={ref}
type={props.type}
placeholder={props.placeholder}
{...props}
/>
);
}
);
export default Input;

Footnotes

  1. Function components cannot be given refs. Attempts to access this ref will fail (opens in a new tab)