Blog
🚀 React performance quick wins 🚀 - 7 easy ways to improve your React performance - part 1
At the beginning of the year I wrote a blog post about React performance improvements. It‘s one of my favourite blog posts I ever wrote. It’s a great example of documenting everything while you learn it.
It’s a very in depth analysis. It shows you how to test and measure the performance of your React application and a lot of ways how to improve it. In the contrary this blog post has the goal to give you a lot of quick wins for your performance. Things you can change and adjust, without too much effort.
So you can see it as an addition to my original react performance blog post. The first one builds the foundation. This one adds the cherry on top.
This post is part 1 of a series.
Part 2: 7 easy ways to improve your React performance - part 2
What you can learn from this blog post:
- Always use a key when mapping (and not index)
- Use React.Fragments instead of divs as parent element
- One useState hook instead of multiple for connected data
Always use a key when mapping (and not an index)
When mapping over an array and rendering a list of items, make sure you always use keys for every item.
Keys help React identify which items have changed, are added, or are removed. Keys should be strings that identify a list item, such as an ID.
Here is a quick example of the usage of keys. Check the return method of this component. There we use the id of every animal as a key.
import * as React from 'react'
import { AnimalCard } from './animal-card'
const animals = [
{
id: 1,
name: 'dog',
},
{
id: 2,
name: 'cat',
},
{
id: 3,
name: 'unicorn',
},
]
const Animals = () => {
return animals.map((animal) => {
return <AnimalCard key={animal.id}>{animal.name}</AnimalCard>
})
}
export default Animals
If you're not using keys, React has to a hard time to figure out which items to update. This can lead to updating every item although only one changed.
This can be a massive performance impact! 😫
If you don't have access to unique identifiers, indexes can be used as a last resort. It is not recommended to use them as keys but it's better than not using any keys at all.
If the order of items changes, the index changes as well so React has to update every item anyway.
You can learn more about why keys are important in this article about reconciliation Opens in new tab.
So that's it for quickwin number one: always use a key when mapping!
Use React.Fragments instead of divs as JSX parent element
Next up: quickwin number two.
When you return multiple elements from a component, JSX needs a parent element
to wrap them. A quick way to do this, is to put a <div>
around them.
I admit it, I've done this too, way too many times.
import * as React from 'react'
const MyComponent = () => {
return (
<div>
<span>Hi!</span>
<span>Hope you can learn a lot from my blog posts</span>
</div>
)
}
export default MyComponent
But the next time you need a JSX wrapping element, think again! You can use a React.Fragment for that!
import * as React from 'react'
const MyComponent = () => {
return (
<React.Fragment>
<span>Hi!</span>
<span>Hope you can learn a lot from my blog posts</span>
</React.Fragment>
)
}
export default MyComponent
And the best thing is, there is even a short syntax for this.
import * as React from 'react'
const MyComponent = () => {
return (
<>
<span>Hi!</span>
<span>Hope you can learn a lot from my blog posts</span>
</>
)
}
export default MyComponent
But wait, why does this boost my performance? Good question! Here's the thing. The more DOM elements your React application has, the longer the render process takes.
Google's performance tool lighthouse recommends not more than 1500 DOM nodes in total.
So by removing every unnecessary div
, like the one we've used way too often as
a JSX parent element wrapper, we already get closer to that goal. And we can
boost our performance!
You can read more about why you should avoid too many DOM nodes in this article: https://web.dev/dom-size/ Opens in new tab
Hi Friend!
If you enjoy my writings and learn something from them, you can consider to support me! One way of doing this is just as easy as buying me a Coffee!
Thanks so much! This means a lot to me and is a great way to support my work.
☕️ Buy me a coffee ☕️One useState hook instead of multiple for connected data
Another performance quickwin you can achieve easy, is using one useState
hook
instead of multiple ones for connected data.
Imagine a developer built a form with several input
elements. Therefore they
added four individual useState
hooks.
That could look something like this:
import * as React from 'react'
const MyBigForm = () => {
const [username, setUsername] = React.useState('')
const [email, setEmail] = React.useState('')
const [password, setPassword] = React.useState('')
const [nickname, setNickName] = React.useState('')
const handleUserNameChange = (event) => {
setUsername(event.target.value)
}
const handleEmailChange = (event) => {
setEmail(event.target.value)
}
const handlePasswordChange = (event) => {
setPassword(event.target.value)
}
const handleNicknameChange = (event) => {
setNickName(event.target.value)
}
return (
<form>
<label>Username:</label>
<input
value={username}
name="username"
onChange={handleUserNameChange}
/>
<label>Email:</label>
<input
value={email}
name="email"
onChange={handleEmailChange}
/>
<label>Password:</label>
<input
value={password}
name="password"
onChange={handlePasswordChange}
/>
<label>Nickname:</label>
<input
value={nickname}
name="nickname"
onChange={handleNicknameChange}
/>
</form>
)
}
There is a lot of useState
and onChange
going on here, right? Phew. We can
optimize for the better here!
By removing the individual useState
hooks and implementing a combined one,
we're making sure to reduce the size of the component and therefore improve
the performance.
And we can also get rid of all the handleChange
functions, which all seem to
do the same.
import * as React from 'react'
const MyBigForm = () => {
const [formdata, setFormdata] = React.useState({
username: '',
email: '',
password: '',
nickname: '',
})
const handleOnChange = (event) => {
setFormdata({
...formData,
[event.target.name]: event.target.value,
})
}
return (
<form>
<label>Username:</label>
<input
value={username}
name="username"
onChange={handleOnChange}
/>
<label>Email:</label>
<input
value={email}
name="email"
onChange={handleOnChange}
/>
<label>Password:</label>
<input
value={password}
name="password"
onChange={handleOnChange}
/>
<label>Nickname:</label>
<input
value={nickname}
name="nickname"
onChange={handleOnChange}
/>
</form>
)
}
Wow a lot less code and a lot more readable, don't you think? It's always a good idea to keep your state in an object, if you're dealing with connected data.
Don't get me wrong: using and calling multiple useState
hooks is not a bad
thing! React has no problem with that.
But in this example it's also about removing duplicate code and rethinking your components.
And if JavaScript has to allocate the memory for only one function instead of four, that's also a performance quickwin! And that's what we're here for, right?
That's it for part 1 of this React performance quickwins series! Hope you could already apply some of them and make your React app even faster.
Let me know if these tips helped or you have other tips, you'd like to share.
Just send me an email Opens in new tab or message me on Twitter Opens in new tab.
I hope you enjoyed this post and learned something new. If you have any questions, feel free to reach out to me via Email Opens in new tab.
If you want to support me, you can buy me a coffee. I would be very happy about it!
☕️ Buy me a coffee ☕️I wish you a wonderful day! Marco