What is it for the "current" key in useRef hook?

Viewed 1301

Reading the React documentation, there is a very useful hook to save the state or reference of a variable before the possible refresh of the component.

I understand perfectly this hook except for one question, and that is why it has to have a "current" value instead of being the variable that I want to save?

What I am expecting:

    const myVar = useRef('Hello world!');
    return <h1>{myVar}</h1>

What actually is:

    const myVar = useRef('Hello world!');
    return <h1>{myVar.current}</h1>
2 Answers

In React, changes in state force a component to re-render. A ref is for something you want to store that won't force a re-render even if does change. Typically, a DOM node.

Making this work requires a bit of indirection. The ref itself is always the same object. However the ref's properties - i.e. the current attribute - may change.

It might look like unnecessary in your example, where you only read the ref, but it becomes important and understandable, if you consider that you also want to set a value to the ref.

If the react-people would have implemented useRef without the .current, it actually would work if you never have to set the value (in runtime). But then you wouldn't need a ref at all. E.g. then your example could perfectly fine be written as just:

const myVar = 'Hello world!';
return <h1>{myVar}</h1>

But you always need to set some value to the ref, and that would just be not possible without the .current.

Here I show some examples to illustrate what would have happened, if the react-people would have done it without .current:

example 1: set myVar.current

e.g. consider this working example:

// in the first run of the component:
const myVar = useRef('old value'); // myVar === useRef_returnValue === { current: 'old value' }
myVar.current = 'new value';       // myVar === useRef_returnValue === { current: 'new value' }

// in the next run of the component:
// myVar is a reference to the same,
// now changed useRef_returnValue === { current: 'new value' }
const myVar = useRef('old value'); 

// (Note that 'old value' in useRef('old value') is only the initial value,
// which doesn't matter anymore after the first run.)

That would not work if it was without the .current:

// in the first run of the component:
let myVar = useRef('old value');  // myVar === useRef_returnValue === 'old value'
myVar = 'new value';              // myVar is a completely new string 'new value', no reference to the useRef_returnValue anymore.

// in the next run of the component:
// myVar is a reference to the same,
// unchanged useRef_returnValue, still with value 'old value'.
let myVar = useRef('old value');

example 2: ref-property

Even in cases where you might think you never want to set a value, e.g.:

const inputRef = useRef();
return <input ref={ inputRef } />;  // input.ref becomes the internal useRef-object

the input component needs something it can attach itself to. E.g. a fictional implementation might look something like:

const input = function( props ){
  const thisDomObject = thisDomObject();
  if( props.ref ){
    // input.ref.current becomes thisDomObject,
    // input.ref is the internal useRef-object, so
    // (useRef-object).current also becomes thisDomObject
    props.ref.current = thisDomObject;
  }
};

This would not work without the .current:

// input.ref was the internal useRef-object, and now becomes thisDomObject.
// The internal useRef-object stays unchanged.
props.ref = thisDomObject;

Remark:

I think the property name "current" is just a more or less arbitrarily choosen name that doesn't matter. The only important thing is, that it is a property.

Related