Using block-scoped variable at the module level
Tags: discuss, react
Published: 2020-11-26 11:26:06

---
title: Using block-scoped variable at the module level
published: true
description: Is there a case for using let or var at the module level of a React component? Is this categorically an antipattern? Discuss
tags: #discuss, #react
---

I was doing some code review today, and I found myself correcting a relatively junior dev's code, leaving the message, "Using let outside the component scope tends to be an antipattern. Use a useRef or a useState inside the component scope instead."

I think that this is generally true, and it was definitely true in the case of the other dev (they should have been using `useState` in this case). But I got to asking myself whether it is globally true. Is using block-scoped variables at the module level of React components, generally, an anti-pattern?


###  An example

For the purposes of demonstrating what I'm talking about, imagine the following code.

```jsx
// MyComponent.js
import React, { useState } from "react";

let blockScopedVal = 0;

export default () => {
  const [myVal, setMyVal] = useState(0);
  
  return (
    <div>
      <button onClick={() => blockScopedVal ++)}>blockScopedVal: {blockScopedVal}</button>
      <button onClick={() => setMyVal((old) => old + 1)}>myVal: {myVal}</button>
    </div>
  );
};

```

There are two basic implications of this code:

**First**, clicking on the first button will not cause a rerender of the component, similar to as if I had used a `useRef`.

For example, if I click the first button 10 times, I won't notice anything change in the UI, but when I click the second button, the first button's displayed value will jump to 10 and the second button's displayed value will increment correctly to 1. 

![Example 1](https://dev-to-uploads.s3.amazonaws.com/i/ro6dlqw37z82d7jjhlqb.png)



**Second**, if you have more than one `<MyComponent />`, they will share the variable `blockScopedVal` behind the scenes. 

For example, imagine that I have two `MyComponent`s. If I click the first button (the blockScopeVal incrementer) of the `MyComponent` 10 times, I won't notice anything change in the UI, but when I click its second button, the first button's displayed value will jump to 10 and the second button's displayed value will increment correctly to 1. The second `MyComponent` will still be at "blockScopedVal: 0" "myVal: 0". But, if I click the second `MyComponent`'s second button, I'll have "blockScopedVal: 10" "myVal: 1". The `blockScopedVal`'s value is shared between the two instances.

This is where using a block-scoped variable differs significantly from using a `useRef`. 

![Example 2](https://dev-to-uploads.s3.amazonaws.com/i/4wxjb2qa1mteo5acmlfu.png)

### The question(s)

Is using block-scoped variables in React component modules an anti-pattern? If so, why? If not, what are some use cases?

My "don't do this" alarm went wild when I saw the `let` during code review, and in the case I was presented, my intuition was completely right, but I was unable to say why *a priori* this is definitively an antipattern. Imagine that you **do** want to share scope across all instances of the same component and only across the instances of that component [^1] Is there any good reason not do to it this way, instead of reaching for some slick library?

I guess the difficulty is that I can't think of a great use case. Can any of you? Or, conversely, can you explain why we should never do this, ever?

I look forward to hearing from you all, and if you want to play around with the concept a bit, I made a [code sandbox](https://codesandbox.io/s/restless-water-nh527?file=/src/App.js).




[^1]: ... and to do so in a way that doesn't trigger rerenders. Ok I might be reaching here since the number of use cases seems to be diminishing before my eyes. But still. Imagine.