admin管理员组文章数量:1134249
I am trying to understand "forwardRef" more deeply referring the below page; /learn/manipulating-the-dom-with-refs
Here it is mentioned that A component doesn’t expose its DOM nodes by default. You can opt into exposing a DOM node by using forwardRef and passing the second ref argument down to a specific node.
My question is say for the example below;
import { forwardRef, useRef } from 'react';
const MyInput = forwardRef((props, ref) => {
return <input {...props} ref={ref} />;
});
export default function Form() {
const inputRef = useRef(null);
function handleClick() {
inputRef.current.focus();
}
return (
<>
<MyInput ref={inputRef} />
<button onClick={handleClick}>
Focus the input
</button>
</>
);
}
We have
const MyInput = forwardRef()
But shouldn't function Form() be specified also with forwardRef(), since inside Form component definition also, we have below i.e. it is also passing down it's ref attribute.
<MyInput ref={inputRef} />
Basically, I am trying to understand where/how exactly is the "forwardRef" specified.
P.S: I understand things are different with the latest React v19, but just trying to understand since I have apps on older React versions;
I am trying to understand "forwardRef" more deeply referring the below page; https://react.dev/learn/manipulating-the-dom-with-refs
Here it is mentioned that A component doesn’t expose its DOM nodes by default. You can opt into exposing a DOM node by using forwardRef and passing the second ref argument down to a specific node.
My question is say for the example below;
import { forwardRef, useRef } from 'react';
const MyInput = forwardRef((props, ref) => {
return <input {...props} ref={ref} />;
});
export default function Form() {
const inputRef = useRef(null);
function handleClick() {
inputRef.current.focus();
}
return (
<>
<MyInput ref={inputRef} />
<button onClick={handleClick}>
Focus the input
</button>
</>
);
}
We have
const MyInput = forwardRef()
But shouldn't function Form() be specified also with forwardRef(), since inside Form component definition also, we have below i.e. it is also passing down it's ref attribute.
<MyInput ref={inputRef} />
Basically, I am trying to understand where/how exactly is the "forwardRef" specified.
P.S: I understand things are different with the latest React v19, but just trying to understand since I have apps on older React versions;
Share Improve this question asked Jan 7 at 18:48 copenndthagencopenndthagen 50.7k105 gold badges311 silver badges485 bronze badges2 Answers
Reset to default 4You are defining inputRef
at the parent level which will reference <input>
element at the child level via the forwardRef
.
In your case, Form()
is a parent component and MyInput
is the child component.
So Form()
wouldn't need a ref
passed to it. It defines it via useRef
instead. MyInput
would need ref
passed down from the parent component definition and forwardRef
wrapping it in its own definition.
The confusion may be coming from not realizing forwardRef
is a a function that will return a React element which is "the child element" you want to reference at the parent level.
But shouldn't function Form() be specified also with forwardRef(), since inside Form component definition also, we have below i.e. it is also passing down it's ref attribute
Answer to the question is :
a. As the parent component of Form component has not requested DOM element access to it, it should not wrap in forwardRef.
b. We need to wrap MyInput in forwardRef:
b.1) Since its parent Form component has requested DOM element access to it.
b.2) The component MyInput cannot provide DOM access by itself since it is a function component.
c. We do not need to wrap input element in forwardRef, since it is not a function component therefore it can directly provide access to its DOM element.
A detailed answer:
The above point quoted from your post, may be better discussed under the background of a component having nested components in 2 levels.
Please see below an example of this kind:
App.js
import { forwardRef, useRef } from 'react';
export default function App() {
return <Form />;
}
function Form() {
const sectionRef = [useRef(), useRef()];
function handleReset() {
sectionRef[0].current.value = '';
sectionRef[1].current.value = '';
}
return (
<>
<h1>Form A</h1>
<button onClick={handleReset}>Reset all Sections</button>
<MySection ref={sectionRef[0]} title="Section 1" />
<MySection ref={sectionRef[1]} title="Section 2" />
<br />
<br />
</>
);
}
MySection = forwardRef(MySection);
function MySection({ title }, ref) {
function handleReset() {
ref.current.value = '';
}
return (
<>
<h2>{title}</h2>
<MyInput ref={ref} />
<br />
<button onClick={handleReset}>Reset this Section</button>
</>
);
}
MyInput = forwardRef(MyInput);
function MyInput(props, ref) {
console.log(undefined);
return (
<>
<label>
Input 1:
<input ref={ref}></input>
<br />
<i>more inputs follow here...</i>
</label>
</>
);
}
Test run - Output
Observation:
The button at the form level will clear inputs in all sections. Similarly, the button in each section will clear the input with respect to each section. Therefore the component has been found functioning well as intended.
Let us now view the Render Tree of the sample App. It will assist us to get a clear view of the data flow discussed in the coming sections.
The Render Tree
/*
App // root component
Form // 1st level
MySection // 2nd level
MyInput // 3rd level
*/
Let us start discussing the code.
React documentation states this:
...A component can specify that it “forwards” its ref to one of its children.
Let us inspect how will this statement hold true in each component in the app.
1. Root component
This component neither receives nor defines a ref object. Therefore it does come under the discussion.
2. Form component
This component does not receive a ref object. However it defines two ref objects. And it also declares two children, and it then requests to get access to each child component by the following statement.
It means the code intends to get reference to each MySection component. However, as we know, MySection is a function component. A function component may or may not have a single representation in DOM. It means that a function component may be composed of other function components as well as HTML elements. For security reasons also React does not allow cross component DOM elements access. Therefore the intent of the code can be fulfilled only with additional instructions in the source program.
...
<MySection ref={sectionRef[0]} title="Section 1" />
<MySection ref={sectionRef[1]} title="Section 2" />
...
Therefore we are in need of the function forwardRef here as below.
MySection = forwardRef(MySection);
function MySection({ title }, ref) {
...
<MyInput ref={ref} />
...
}
By the code, we could make the call to forwardRef and could get the ref in Form component made available in MySection as well, by the props ref. Now let us see what happens in MySection component.
3. MySection component
Here in this component, the very same ref received has been used to get access to the function component MyInput. Please note that there is no new ref object defined in this component. It references the very same ref object it received as its ref prop.
However the same issue happens here as well. MyInput is a function object which is comprised of another function component MyInput. Therefore we need to provide further instructions as below.
MyInput = forwardRef(MyInput);
function MyInput(props, ref) {
...
<input ref={ref}></input>
...
}
By the code, we could make the call to forwardRef and could make the same ref in MySection, available in MyInput as well, by the props ref. Now let us see what happens in MyInput component.
4. MyInput component
MyInput receives the same ref passed through MySection. However this function component contains the HTML element into which the access has been requested by Form component. Therefore it can fulfil the request without any additional forward calls. Therefore the following line of code actually fulfils the request for access.
...
<input ref={ref}></input>
...
Final notes:
Please take note that there are only two ref objects created in the entire app, which have been defined in Form component. MySection as well as MyInput components are just receiving the same ref, since it forward the ref. And finally MyInput fulfils the request for access.
Though we say it fulfils the request for access, during the entire rendering of the App, the value in these two ref in all components will be undefined. The reason for that is that ref objects are set by React only during the commit stage which follows rendering stage. It means only during commit, the DOM elements are created or updated.
Some related references, may be useful
value of using React.forwardRef vs custom ref prop
forwardRef - a simple alternative - code
React - Forwarding multiple refs
本文标签: reactjsReact forwardRef for any componentStack Overflow
版权声明:本文标题:reactjs - React forwardRef for any component - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736781322a1952612.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论