Quick Tip - Memoizing change handlers in React Components
Tags: react, memoization, optimization
Published: 2018-10-01 15:58:49

---
title: Quick Tip - Memoizing change handlers in React Components
published: true 
description: 
tags: [react, memoization, optimization]
canonical_url: https://blog.robertbroersma.com/quick-tip-memoizing-change-handlers-in-react-components
---

Let's consider a basic form with a controlled component in `react`:

```react
class Form extends React.Component {
  state = {
    value: '',
  };

  handleChange = e => {
    this.setState({
      value: e.target.value,
    });
  };

  render() {
    return (
      <div>
        <InputComponent type="text" value={this.state.value} onChange={this.handleChange} />
      </div>
    )
  }
}
```
We keep a state, pass the value to our `InputComponent`, and update the value with the value we get from it.

Now consider this larger form. I like to use this arrow-function-that-returns-another-arrow-function (what do you call this?) syntax for brevity and to not have to repeat myself with multiple change handlers.
```react
class BiggerForm extends React.Component {
  state = {
    a: '',
    b: '',
    c: '',
  };

  handleChange = key => e => {
    this.setState({
      [key]: e.target.value,
    });
  };

  render() {
    return (
      <div>
        <InputComponent type="text" value={this.state.a} onChange={this.handleChange('a')} />
        <InputComponent type="text" value={this.state.b} onChange={this.handleChange('b')} />
        <InputComponent type="text" value={this.state.c} onChange={this.handleChange('c')} />
      </div>
    )
  }
}
```
Looks easy, right? The problem with this is that `this.handleChange()` will create a new function every time it is called. Meaning everytime BiggerForm re-renders, all the `InputComponents` will re-render. Meaning EVERYTHING will re-render on EVERY keystroke. You can imagine what this would do to a huge form.

Now what we could do is either split `handleChange` into specific change handlers, e.g. `handleChangeA`, `handleChangeB`, `handleChangeC`, and this would solve our issue. But this is a lot of repetition, and considering we are considering huge forms; a lot of tedious work.

Luckily there's this thing called memoization! Which in short is a caching mechanism for our functions. Sounds fancy, but all it does is remember which arguments yield what result when calling a function. When the function is called again with the same arguments, it will not execute the function, but just return the same result. In our example:
```react
class MemoizeForm extends React.Component {
  state = {
    a: '',
    b: '',
    c: '',
  };

  handleChange = memoize(key => e => {
    this.setState({
      [key]: e.target.value,
    });
  });

  render() {
    return (
      <div>
        <InputComponent type="text" value={this.state.a} onChange={this.handleChange('a')} />
        <InputComponent type="text" value={this.state.b} onChange={this.handleChange('b')} />
        <InputComponent type="text" value={this.state.c} onChange={this.handleChange('c')} />
      </div>
    )
  }
}
```
That was easy! In this example, on the first render of `MemoizeForm`, the `handleChange` function is called for every `InputComponent` with their specific key as an argument. Whenever `MemoizeForm` re-renders, `handleChange` is called again. However, since it's called with the same argument as before, the memoization mechanism returns the same function (with the same reference), and the `InputComponent` is not re-rendered (unless the value is changed ofcourse!).

🎉

P.S. Any memoization library will do, I like to use [fast-memoize](https://github.com/caiogondim/fast-memoize.js/)

-- EDIT --

I've only recently learned that `event.target` contains a lot more stuff! Using hooks you could just do:

```javascript
const [state, setState] = useState(initialValues)

const handleChange = useCallback(e => {
  setState(values => ({ ...values, [e.target.name]: e.target.value }))
}), [])
```