DEV Community

loading...

Using React.useMemo for optimization and logic reuse

Favour Afolayan
Updated on ・3 min read

Purity

VueJS, other than being reported to having a low learning curve, its reactivity system is arguably the most important concept in it.
At the heart of its reactivity system is the concept of computed properties:

What is a computed property?

In layman's terms, a computed property is simply an expression that returns a particular value by computing it from some variables/dependencies.

Let's see a vue js example:

<div id="example">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>

var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    // a computed getter
    reversedMessage: function () {
      // `this` points to the vm instance
      return this.message.split('').reverse().join('')
    }
  }
})

// originalMessage = 'Hello'
// reversedMessage = 'olleH'
Enter fullscreen mode Exit fullscreen mode

This simple, yet clean concept can be used to encapsulate long or expensive logic that needs to be re-calculated when some variables change. From the example above, if the value of message changes, Vue recalculates the value of reversedMessage and returns the new value based off of that.
Importantly, it caches/memoizes the value until any dependency changes.

Bringing the idea into react

One of the biggest frustrations I have had with React codebases has always been having expensive or some lines of code that should go into a function embedded within the template/markdown of a component and I am super excited to find out that React.useMemo can easily be used to clean this up.

Let's modify the reversedMessage example above with some new requirements:

  1. The message length must be > 5
  2. Show the reversed message in uppercase

Implementing this without useMemo

import { useMemo, useState } from "react";

export default function App() {
  const [message, setMessage] = useState("");

  return (
    <div>
      <h2>Reversed Message Component</h2>
      <input
        value={message}
        onChange={(event) => setMessage(event.target.value)}
      />

      <p>Original Message: {message}</p>
      <p>Reversed Message: 
      {message && message.length > 5 
 ? message.split("").reverse().join("").toUpperCase(): ''}</p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Some drawbacks with this implementation:

  1. If this was an expensive logic, it is not reusable
  2. The template will keep increasing with every new modification to the requirement.
  3. It is not clean.

Imagine completing this and after a week, management added a new requirement:

  1. show the number of characters inputed
  2. if the characters provided is a palindrome, let's show a message to the user.

Now, we go back to that lengthy section and add more logic to it and it becomes more complex to read and understand. I am sure you are probably thinking, dude! just tuck this behind a function and rest. Yes, that is somewhat what we will be doing with useMemo but even better, we will make it into a computed property that can be reused for anything else.

Implementing with useMemo

import "./styles.css";

import { useMemo, useState } from "react";

export default function App() {
  const [message, setMessage] = useState("");

  const reversedMessage = useMemo(() => {
    if (message.length > 5) {
      // we can keep extending this functionality to any length
      return message.split("").reverse().join("").toUpperCase();
    }

    return "";
  }, [message]);

  return (
    <div>
      <h2>Reversed Message Component</h2>
      <input
        value={message}
        onChange={(event) => setMessage(event.target.value)}
      />

      <p>Original Message: {message}</p>
      <p>
        Reversed Message:
        {reversedMessage}
      </p>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

Now the reversedMessage variable can be used to do different things within that component and we get the advantage of memoization right out of the box from React. This ensures that the part of the component using the reversedMessage gets the latest value every time and React doesn't re-compute it every time except when any of the dependencies listed in the array changes.

You can read more about useMemo and other optimization techniques in React from the Official React Documentation

Discussion (2)

Collapse
r0zar profile image
Ross Ragsdale

Well put! Enjoyed the examples a lot. It really made it clear how you explained useMemo within the use-case of reusable template logic. That really clicked with me. That was something that existed in angularjs as "filters" as well, but didn't realize until your post that useMemo is the React equivilent.

Collapse
igbominadeveloper profile image
Favour Afolayan Author

Thanks @r0zar . I am glad you found it useful.
Fun fact: I wrote a draft for this article about 3 months ago but I couldn't get it out because I didn't know that useMemo could be used to get this functionality in React. These weekly goals are lit