简体   繁体   中英

current is always null when using React.createRef

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

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.

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.

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.

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

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

This may happen in the following circumstances:

  • You have forgotten to pass your ref to the component ie 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

ie: 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

In version 17.0.2 of React, refs and it being asynchronous got changed. Code like this stopped working properly after the update:

import {useRef} from 'react';
import './kind.css'

const Kind = ({prop}) => {

    // defining the ref
    const kindRef = useRef('')
    
    // print the ref to the console
    console.log(kindRef)


    return (
    <div ref={kindRef} className="kind-container" >
        <div className="kind" data-kind='drink'>Drink</div>
        <div className="kind" data-kind='sweet'>Sweet</div>
        <div className="kind" data-kind='lorem'>lorem</div>
        <div className="kind" data-kind='ipsum'>ipsum</div>
        <div className="kind" data-kind='ipsum' >food</div>
    </div>
    );
}

export default Kind;

After initializing the ref it takes sometime to assign it to the dom. Javascript, being a synchronous language, doesn't wait for the ref to initialize and skips straight to the log.

To fix this we will need to use useEffect like this

import { useRef, useEffect} from 'react';
import './kind.css'

const Kind = ({prop}) => {

    // defining the ref
    const kindRef = useRef('')
    
    // using 'useEffect' will help us to do what ever you want to your ref varaible,
    // by waiting to letting the elements to mount:'mount means after the elements get inserted in the page' and then do what you want the ref
    useEffect(()=>{

        // print the ref to the console
        console.log(kindRef)        

    })


    return (
    <div ref={kindRef} className="kind-container" >
        <div className="kind" data-kind='drink'>Drink</div>
        <div className="kind" data-kind='sweet'>Sweet</div>
        <div className="kind" data-kind='lorem'>lorem</div>
        <div className="kind" data-kind='ipsum'>ipsum</div>
        <div className="kind" data-kind='ipsum' >food</div>
    </div>
    );
}

export default Kind;

useEffect waits to the ref to be assigned to the DOM element and then runs the function assigned to it.

If you are using the ref in useCallback (or another hook), remember to add the ref to the dependencies:

const doSomething = useCallback(() => {
 ref.current?.doIt();
}, [ref]);
<div ref={this.test}>

You have to assign ref prop to your DOM element. In this case you have to assign ref to div element

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM