Case I, I can accept those code as the picture shows, we define the ref in parent component and pass it to child component
App.js
import { useRef } from 'react';
import MyInput from './MyInput.js';
export default function Form() {
const ref = useRef(null);
function handleClick() {
ref.current.focus();
}
return (
<form>
<MyInput label="Enter your name:" ref={ref} />
<button type="button" onClick={handleClick}>
Edit
</button>
</form>
);
}
MyInput.js
import { forwardRef } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
const { label, ...otherProps } = props;
return (
<label>
{label}
<input {...otherProps} ref={ref} />
</label>
);
});
export default MyInput;
Case II,the component Input was defined as following ,
import * as React from 'react'
import { cn } from '@/lib/utils'
export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {}
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
className
)}
ref={ref}
{...props}
/>
)
}
)
Input.displayName = 'Input'
export { Input }
this was used in another file chat.js, the episoid as follwing
import { Input } from './ui/input'
<Input
value={previewTokenInput}
placeholder="OpenAI API key"
onChange={e => setPreviewTokenInput(e.target.value)}
/>
something confused me , the parent didn't define Ref variable, and use directly . Is this a new approach of using forwardRef ?
the codes are from https://github.com/vercel-labs/ai-chatbot,
Something confused me, the parent didn't define Ref variable, and use directly.
Just because a child component forwards a React ref doesn't mean a parent component necessarily needs to pass one. React components generally ignore props they don't care about, and for those props that are not passed their values will simply be undefined or receive a default/fallback value if that is how the child component was implemented.
Is this a new approach of using forwardRef?
No, this is always how the React.forwardRef
function worked.
There is no difference between the two components in terms of "cases".
import { forwardRef } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) { // ref forwarded
const { label, ...otherProps } = props;
return (
<label>
{label}
<input
{...otherProps}
ref={ref} // passing ref through to HTML element
/>
</label>
);
});
export default MyInput;
const Input = React.forwardRef<HTMLInputElement, InputProps>( // ref forwarded
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
'....',
className
)}
ref={ref} // passing ref through to HTML element
{...props}
/>
)
}
)
In terms of forwarding React refs, the "cases" are identical.
What is different between the two though is in the first example, the code is actually creating a ref and passing it to the MyInput
component.
import { useRef } from 'react';
import MyInput from './MyInput.js';
export default function Form() {
const ref = useRef(null); // <-- created ref
function handleClick() {
ref.current.focus();
}
return (
<form>
<MyInput label="Enter your name:" ref={ref} /> // <-- passed ref
<button type="button" onClick={handleClick}>
Edit
</button>
</form>
);
}
The same could be done with the second code example:
import { useRef } from 'react';
import { Input } from './ui/input';
export default function Form() {
const ref = useRef(null);
function handleClick() {
ref.current.focus();
}
return (
<form>
<Input
value={previewTokenInput}
placeholder="OpenAI API key"
onChange={e => setPreviewTokenInput(e.target.value)}
ref={ref}
/>
<button type="button" onClick={handleClick}>
....
</button>
</form>
);
}