Why can't you pass a ref to a functional component in react?
Asked Answered
H

3

15

Why can't you pass a ref to a functional component in react?

What is different in function components compared to class components that you can't pass a ref to it?

Why is that not possible?

Notes: I'm making this question, because I always saw explanations about how to use ref with functional components, and that you need to use fowardRef, but no one explained how react handles functional components making it not possible to pass a ref to it, it's always explained how to do it, but never why you need to do it.

Hyp answered 27/1, 2021 at 11:29 Comment(0)
I
7

When you pass ref to a class component, it's made to point (via ref.current) to the actual class instance. (See "Accessing Refs" in the legacy React documentation.) That lets you access the fields of that instance. But function components don't have instances or fields, so there's nothing for ref to point to, and nothing it could be used for.

And, to be clear, forwardRef doesn't really change that. forwardRef still doesn't let ref point to the instance, because there still isn't one. Instead, forwardRef lets you "forward" the ref to another object: either a nested component (typically a DOM element), or a custom object that you define (using useImperativeHandle).

Presumably, if React were being designed from scratch today, ref would be done a bit differently. But because of its history — because it has a special meaning for class components — ref is reserved.

You can, however, use another prop name like innerRef and use it for forwarding, as discussed at Why, exactly, do we need React.forwardRef?.

Implicate answered 27/1, 2021 at 12:54 Comment(5)
The "more detailed answer" this answerer linked to contains comments from THIS ASKER, requesting to understand WHY this is the case. And instead of answering this question here, the answerer regurgitated their explanation that it is not possible and then linked back to the question where the answerer encouraged the asker to ask this question somewhere else. I STILL don't understand WHY ref can't be passed to a function component.Chemism
Yes the original question was asked in the comments, but you suggested it should be asked separately, presumably because you felt it was a different question with a different answer. But you did not provide a different answer here. You provided a shorter version of the same answer. The question here is WHY was the decision made to not allow ref as a prop. And your answer simply states that it won’t work. I will not be asking a separate question, as this question deserves an appropriate answerChemism
It would be helpful to understand the reason behind the decision, instead of the technical reason it can’t be done.Chemism
@ChristopherMeyers "The question here is WHY was the decision made to not allow ref as a prop" are you asking, why the ref prop is preserved in function components?Implicate
@ChristopherMeyers: FWIW, I've edited this answer in a way that should, I believe, address your concerns.Wet
D
2

I search on google with the same question: Why cannot pass ref like a props in React? And i find out the answer at React documentation:

There is one caveat to the above example: refs will not get passed through. That’s because ref is not a prop. Like key, it’s handled differently by React. If you add a ref to a HOC, the ref will refer to the outermost container component, not the wrapped component.

https://reactjs.org/docs/forwarding-refs.html

I hope that can give you a safisfactory answer!

Dethrone answered 9/11, 2022 at 4:40 Comment(0)
F
0

Because, it doesn't make much sense for function components as they don't have this. On the other hand using ref on a class component is essentially gonna bind refObj.current to the class's instance(this) itself and access public fields and methods but not static properties/methods of that class. To elaborate on this, consider the following example:

//import { Component, createRef } from 'react';

class Mybtn extends React.Component {
   constructor(props) {
      super(props);
    }
  myprop = 33;         //Is  accessible via ref attribute
  static myprop2 = 44; //not accessible via ref attribute
  Log(){
    console.log(this.props);
  }
  render(){    
    return (      
      <button>test</button>
    )
  }
}


function Mybtn2() {
  return <button>TTT</button>;
}


class Form extends React.Component {
  inputRef = React.createRef();

  handleClick = () => {    
    this.inputRef.current.Log(); //same as calling this.Log() from inside Mybtn
    console.log(this.inputRef.current.myprop);  //instance's field
    console.log(this.inputRef.current.myprop2); //can't access static fields, but can access instance's field 
  }

  render() {
    return (
      <div>
        <input ref={this.inputRef2} />
        <button onClick={this.handleClick}>
          Handle click
        </button>
        <Mybtn ref={this.inputRef} prop1="tst"></Mybtn>
        <Mybtn2 ref={this.inputRef3} prop1="tst"></Mybtn2>
      </div>
    );
  }
}

//ReactDOM.createRoot(document.getElementById('app').render('Form')

ReactDOM.render(<Form />, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="app"></div>

I am assuming, internally React binds ref attribute to the instance of class. So when it encounters ref on a function component probably babel checks if it's a class-based(instance) component or a function component.

Facsimile answered 5/1 at 12:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.