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'
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:
- The message length must be > 5
- 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>
);
}
Some drawbacks with this implementation:
- If this was an expensive logic, it is not reusable
- The template will keep increasing with every new modification to the requirement.
- It is not clean.
Imagine completing this and after a week, management added a new requirement:
- show the number of characters inputed
- 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>
);
}
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
Top comments (2)
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.
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