Complete useRef() hook with live code examples
Tags: typescript, react, useref, hooks
Published: 2020-03-05 19:52:00

---
title: Complete useRef() hook with live code examples
published: true
description: useRef returns an object with a `current` property. This `current` property gets the initial value of the argument passed to useRef hook
tags: typescript, ReactJS, useRef, hooks
---


### What's up with `useRef` hook?

  `useRef` returns an object with a `current` property. This `current` property gets the initial value of the argument passed to useRef hook. The reference to `{current: <any value>}` object will persist from render to render.

### Is useRef hook used only for accessing Document Object Model(DOM) elements?

  No, useRef hook can also be used as an instance variable.
  
### How can useRef be used as an instance variable? 
  
  The object returned by the `useRef` hook can be used as a container whose `current` property can store a value over the lifetime of the functional component.
  
### The most common use case of `useRef` hook is:

  - Keep a live ref to a `DOMElement`.
  
  ```ts
  function TextInput() {
    const inputEl = useRef(null);
    return (
      <>
        <input ref={inputEl} type="text" />
      </>
    );
  }
  ```
  The important thing here is: 
  ```ts
      const inputEl = useRef(null);
  ```
  and 
```ts
        <input ref={inputEl} type="text" />
```
  After the first render, `inputEl` will have an object with `current` property pointing to our input element.

### Difference between using `useRef` and assigning an ordinary `{current: ...}` object 
  
  [Live example](https://codesandbox.io/s/complete-useref-with-examples-dvlxj)

  As of React documentation, useRef gives us the same object on every render while plain old JS object will just be recreated every render.

#### 1. With useRef
  ```ts

  function setWindowRef<T>(ref: React.RefObject<T>) {
    (window as any).ref = ref;
  }

  function getWindowRef<T>() {
    return (window as any).ref;
  }

  export default function UseRefReact() {
    const [renders, setValue] = React.useState(1);
    const ref = React.useRef(null);

    React.useEffect(() => {
      setWindowRef<HTMLDivElement>(ref);
    });

    return (
      <div className="UseRefReact">
        <div>UseRef with React.useRef(null)</div>
        <button onClick={e => setValue(renders + 1)}> Rerender </button>
        <div ref={ref}>Renders {renders}</div>
        <div>
          {" "}
          {getWindowRef() === ref ? "same ref object" : "ref not set yet"}{" "}
        </div>
      </div>
    );
  }

  ```
  Making use of `const ref = React.useRef(null);` and `<div ref={ref}>Renders {renders}</div>` will give 
  us the reference to that div element.

### How can we check if the object `ref` was changed when our functional component was rendered ?

  Another object persisting between renders will help us check if the `ref` object has changed.
  
  window object enters the scene: 
  ```ts 
  function setWindowRef<T>(ref: React.RefObject<T>) {
    (window as any).ref = ref;
  }

  function getWindowRef<T>() {
    return (window as any).ref;
  }
  ```

  Ok, now that our helper functions are defined, we can move to the next step:

### When do we call our functions?

  - call `setWindowRef` after our component has been rendered
    ```ts
      setTimeout(() => {
        setWindowRef<HTMLDivElement>(ref);
      });
    ```

  - getWindowRef when the view is rendered
```ts
    <div>
        {getWindowRef() === ref ? "same ref object" : "ref not set yet"}
     </div>  
```

  First render we will get `"ref not set yet"`.
### Why?

#### Long answer: 

 - The reason we get "ref not set yet" on first render is because of how JS works under the hood.

#### Short answer:
 - `setTimeout(() => {
        setWindowRef<HTMLDivElement>(ref);
      });
` 
  `setWindowRef` will be queued and executed after we return from our function.

  On any other renderers we will get "same ref object", meaning that indeed React makes sure that we get the same instance with every render.(Thanks React).

#### 2. Without useRef 
```ts
function setWindowObjectRef<T>(ref: React.RefObject<T>) {
  (window as any).objectRef = ref;
}

function getWindowRef<T>() {
  return (window as any).objectRef;
}
export default function UseRefObject() {
  const [renders, setValue] = React.useState(1);
  const ref = { current: null };

  setTimeout(() => {
    setWindowObjectRef<HTMLDivElement>(ref);
  });
  return (
    <div className="UseRefObject">
      <div>UseRef with {`{ current: null }`}</div>
      <button onClick={e => setValue(renders + 1)}> Rerender </button>
      <div ref={ref}>Renders {renders}</div>
      <div>
        {" "}
        {getWindowRef() === ref ? "same ref object" : "ref object changed"}{" "}
      </div>
    </div>
  );
}
```

Examples are pretty much the same.
#### Small differences:
  - `window.objectRef` instead of `window.ref` because we don't what to mess up our example
  - `const ref = { current: null }`; instead of using `React.useRef(null)`

Now, on every render we get "ref object changed" and it seems that we verified how `useRef()` works and why we should use it when we want to persist a value between renders.



### Conclusion:

- `useRef` will always return the same object with the same `current` property value pointing to the same object throughout the lifetime of your functional component.

- even though useRef creates a plain JS object with a `current` property, manually creating an object like
 `{ current: null }`to select a DOM element by passing it to a ref attribute, will not persist the object between renders. 

Article first posted on [danielpdev.io](https://danielpdev.io/)

[Follow me on twitter](https://twitter.com/danielpdev)