# Use setTimeout in React to Defer Logic

# Introduction

`setTimeout` is a very commonly used JavaScript function. It is very useful for many things, such as timing how long an alert should show, or debouncing a button to prevent double clicks.

However when using higher level rendering frameworks like React, Angular, Vue etc, it can give you control over the JavaScript runtime itself to make your life easier!

# A simple problem

Let's take this simple app as an example:

```jsx
export default function App() {
  const [text, setText] = useState("This is some text");
  const [pWidth, setPWidth] = useState(0);
  const pRef = useRef();

  const onTextChange = (changedText) => {
    setText(changedText);
    setPWidth(Math.round(pRef.current.getBoundingClientRect().width));
  };

  return (
    <>
      <div>
        <input value={text} onChange={(ev) => onTextChange(ev.target.value)} />
      </div>
      <p ref={pRef} style={{ display: "inline" }}>{text}</p>
      <p>{pWidth}</p>
    </>
  );
}
```

This app contains an `input` that when changed, runs a function to update the `text` state variable and uses `pRef` to extract the current width of the `p` element and set `pWidth`.

This renders the following:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1660475793906/Slxpo94fZ.png align="center")

`pWidth` is only going to be set when we change the text, so lets delete the text and we should see a width of `0`:

![test.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1660477118476/MufWJ0oXc.gif align="center")

Huh? That's not right! It's showing the width of the `p` element when it had text in it!

This is because when we update `text` via `setText`, React hasn't had a chance to set the text in the `p` element, meaning the width of the `p` element hasn't changed before we set its width using `setPWidth`!

# setTimeout to the rescue!

We can fix this using setTimeout!

Let's change this line:

```jsx
setPWidth(Math.round(pRef.current.getBoundingClientRect().width));
```

To this:

```jsx
setTimeout(() => {
  setPWidth(Math.round(pRef.current.getBoundingClientRect().width));
});
```

And check out output when we clear the input:

![test.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1660477203377/4oJmYtZnu.gif align="center")

And like magic it works as expected!

# Why does this work?

As we have already ascertained, the issue was that we needed to wait until React had actually rendered the text in the `p` element before setting the `p` elements width.

`setTimeout` solves this problem by **deferring** setting the width of the `p` element to the next JavaScript runtime cycle, ensuring that the React has rendered the changes from the previous runtime cycle before running our pending `setTimeout` call-back function.

# Using async/await

This technique can also be used in async functions with the use of a utility function such as:

```jsx
const waitForRender = () => new Promise(res => setTimeout(res));
```

Using the example above, `waitForRender` could be used like this:

```jsx
const onTextChange = async (changedText) => {
  setText(changedText);
  await waitForRender();
  setPWidth(pRef.current.getBoundingClientRect().width);
};
```

This produces the same output!

# Conclusion

That's it! I hope this helped you learn a new technique to add to your toolset when tackling edge case problems that require waiting for a rendering cycle to pass.

Follow me on [Twitter](https://twitter.com/SamDarylDev) to keep up to date with my projects and get notified of new articles like this in the future!
