2 JavaScript memory concerns for React developers
Tags: javascript, typescript, react, performance
Published: 2021-05-01 15:41:15

React provides a superb developer experience: you define states and props, combine components in a way you want — and everything magically updates yet stays consistent. But... What memory effects hide beneath this nice-looking code? Let's see!

# 1. Class members: functions vs arrow functions
Here are two very similar classes. What's the difference?

```javascript
class A {
    x() {
        console.log('Hi!')
    }
}

class B {
    y = () => console.log('Hi!')
}
```

Okay, okay you are right, `y` is `this`-bound 😉 But I wouldn't disturb you with such a trivial thing. There's an interesting memory implication I suggest you to spot.

⏳

⏳

⌛️

`A.x` resides on `A` prototype, and `B.y` copy resides on each `B` instance, meaning `B` instances consume more memory.

Writing the same using only functions makes this more prominent:

```javascript
function A() {
}

A.prototype.x = function() {
    console.log('Hi!')
}

function B() {
    this.y = () => console.log('Hi!')
}
```

`A` instances are completely empty!

## Why is it important?
When implementing React class components we often need `this`-bound functions, and one possible option is an arrow function. In the following example each `Button` instance has its own `handleClick` member:

```jsx
class Button {
    constructor(props) {
        this.props = props
    }
    render() {
        return <button onClick={this.handleClick} />
    }
    handleClick = () => console.log(this.props.message)
}
```

## Is it a problem?
In 99% of cases it's not — an arrow function instance is not that big. Just make sure you don't use it unless you need it. For example, if `handleClick` calls some other class method, it's better be defined as a simple function:

```javascript
class Button {
    // ...
    handleClick = () => this.logMessage()
    logMessage() {
        console.log(this.props.message)
    }
}
```

# 2. Inner functions
What will the following code print? Or, in other words, is inner function referentially the same at each run?

```javascript
function outer() {
    function inner() {
        console.log('Hi!')
    }
    return inner
}

console.log(outer() === outer())
```

⏳

⏳

⌛️

The inner function is referentially different at each run, and the code outputs `false`.

## Why is it important?
Inner functions are the common way to define handlers in React functional components:

```jsx
function Button({message}) {
    function handleClick() {
        console.log(message)
    }
    return <button onClick={handleClick} />
}
```

In this example a new `handleClick` is created on each function run, i.e. on each component render.

## Someone told me `useCallback` can fix this

```jsx
function Button({message}) {
    const handleClick = useCallback(function(m) {
        console.log(m)
    }, [message])
    return <button onClick={handleClick} />
}
```

Now inner `function(m)` is created only when `message` changes, isn't it?

⏳

⏳

⌛️


No, `useCallback` can't override how JavaScript works, and `function(m)` is created at each component render.

## Is it a problem?
Just like in previous example, it's fine in 99% of cases. However, if your handler doesn't need a closure over locals, you may define it outside the component:

```jsx
function Button() {
    return <button onClick={handleClick} />
}

function handleClick() {
    console.log('Hi!')
}
```

## Further reading
[Official explanation on hooks performance](https://reactjs.org/docs/hooks-faq.html#are-hooks-slow-because-of-creating-functions-in-render)
____

*Thanks for reading this. Do you know other JavaScript memory concerns useful to keep in mind?*