current is always null when using React.createRef

71,241

Solution 1

Because you forgot to assign the ref to some dom element. You are only creating it.

Write it like this:

class App extends React.PureComponent {
  constructor(props) {
    super(props);
    this.test = React.createRef();
  }
  handleClick = () => alert(this.test.current.value)
  render() {
    return (
      <div className="App">
        <input ref={this.test} />
        <button onClick={this.handleClick}>Get Value</button>
      </div>
    )
  }
}

Working Example.

Solution 2

I know this is not the solution to OP's problem but for those who are coming from google search, one of the ways the ref.current can be null is that if the component on which the ref is being attached is a connected component. Like with react-redux connect or withRouter. For react-redux the solution is to pass forwardRef:true in the fourth option to connect.

Solution 3

React.createRef() is asynchronous so if you try to access the ref in componentDidMount, it will return null and later return the properties of the component in which you are referencing.

componentDidMount(): void {
      if (this.viewShot && this.viewShot.current) {
          this.viewShot.current.capture().then((uri) => {
        console.log('do something with ', uri);
          });
      }
  }

This is the right way to use the React.createRef() in this context.

Solution 4

You're missing the ref={this.test} prop.

return (
  <div className="App" ref={this.test}>
    current value : {this.test.current + ""}
  </div>
);

Solution 5

This may happen in the following circumstances:

  • You have forgotten to pass your ref to the component i.e this.test from the question.

<Component ref={this.test} />

  • You are using Redux in which the component to which ref props is passed is wrapped by connect method and hence this.test.current would return null as it points to the Redux wrapper, to make this kind of component work make forwardRef: true

i.e: connect(mapStateToProps, mapDispatchToProps, null, {forwardRef: true})(Component)

  • If you are using withRouter and connect together then instead of one here you are having two wrappers and this.test.current would obviously return null, to overcome this make sure withRouter wraps connect

withRouter(connect(mapStateToProps, mapDispatchToProps, null, {forwardRef: true})(Component))

and then

<Component wrappedComponentRef={ref => this.test = ref} />

wrappedComponentRef is a prop used to make the wrapped component available just as forwardRef: true, you can find it in docs here

Share:
71,241

Related videos on Youtube

Sharcoux
Author by

Sharcoux

Updated on August 29, 2021

Comments

  • Sharcoux
    Sharcoux over 1 year

    I was trying to do this.

    I must be missing something, but I don't understand why current is always null in this example.

    class App extends React.PureComponent {
      constructor(props) {
        super(props);
        this.test = React.createRef();
      }
      render() {
        return <div className="App">current value : {this.test.current + ""}</div>;
      }
    }
    

    You can check my test case here

  • Darin Cardin
    Darin Cardin almost 3 years
    I realize this was answered a while ago, but the working example you provided says "current value : null". Shouldn't it give a value?
  • Sharcoux
    Sharcoux about 2 years
    What is this response adding to the selected answer?
  • sandbox992
    sandbox992 almost 2 years
    You're totally wrong! React updates all DOM and refs before componentDidMount fires. What is capture method? It doesn't exist both for 'current' element as ref instance and nor for input element I just can't figure out why there's so much positive review PS: Accepted answer correct!
  • Sharcoux
    Sharcoux over 1 year
    React documentation would encourage you to use useLayoutEffect in this specific case. Also, it's probably safer to log kindRef.current, as the console logs are not static. Finally, It might be a good practice to always specify the dependency array in hooks like useEffect
  • Rojo
    Rojo over 1 year
    As you noticed, I edited your question to better fit the answering guidelines. Your original answer included several grammar mistakes. You also specifically asked for upvotes, which is something that is also against the rules. Finally, you uselessly signed your name in a codeblock. Your username is displayed at the bottom right corner of your answer (above the comments). Please do not rollback your answer to it's original version; I have made changes that are keeping your answer aligned to the guidelines and preventing it from being removed.
  • ammar khaled
    ammar khaled over 1 year
    Thanks bro , I were on hurry
  • Samiksha Jagtap
    Samiksha Jagtap over 1 year
    I am using withTranslation to connect my class component. Cannot pass {forwardRef: true} this one. do you have any idea how can I fix it?
  • Rik Schoonbeek
    Rik Schoonbeek over 1 year
    Super nice to have these things all in one answer