In this article, we'll see some of the common mistakes that React developers make, and how you can avoid them.
So let's get started.
Don't Forget that Every Route Change Mounts and Unmounts a Component
Whenever you're using routing in a React application, you declare routes inside the Switch
component. This means that only one component with the matching route is displayed at a time.
Therefore, whenever you go from one route to another, the previously displayed component is unmounted and the component with the new matching route is mounted.
If you need to persist some data across a route change, you need to declare it in the component which encapsulates the routes. It could be the App
component in the following Code Sandbox, or some other way of persisting data like using local storage or session storage
As you can see in the above Code Sandbox, whenever we change the route by clicking on the links, the corresponding console.log
gets displayed on the console. This indicates that the previous component is unmounted and a new component is mounted.
Don't Use the Wrong setState Syntax
Whenever you declare some state inside a class-based component, it's always an object like this:
this.state = {
counter: 0
}
So whenever you use the updater form of the setState syntax to update the state, it looks like this:
this.setState((prevState) => {
return {
counter: prevState.counter + 1
};
});
Since state is an object, prevState
is also an object – so you access the counter
using prevState.counter
.
But when you're using functional components with React Hooks, the state can be an object or a non-object value as shown below:
const [counter, setCounter] = useState(0);
Here, the value of counter
is not an object but it's a number. So to update the state using updater syntax, you'll write the code like this:
setCounter((prevCounter) => prevCounter + 1);
Here, the prevCounter
is a number. So you don't use prevCounter.counter
– just prevCounter
. Or you can simplify it as shown below:
setCounter((counter) => counter + 1);
Check out my article here for a complete introduction to React state.
Don't Call Hooks from Class Components
Starting with version 16.8.0, React introduced Hooks. They allow you to write better React code and make use of state and component life cycle methods inside functional components.
Check out my article here for an introduction to React hooks.
To make coding easier, React provides many hooks like:
- The
useParams
hook to access URL parameters when using React Routing - The
useHistory
hook to get access to history API inside any component - The
useRef
hook to get access to the DOM element
and many other hooks.
But all of these hooks (which usually start with the use
keyword) work only inside functional components.
If you have a class-based component then you can't use these hooks. You need to refactor your code to convert it to functional components. If you don't, you might get an error like the one in the below screenshot:
Don't Forget to Add a Key Prop When Using the Array map
Method
Take a look at this Code Sandbox Demo.
Here, to display a list of items, you can use the following code:
const Items = ({ items }) => (
<ol>
{items.map((item) => (
<Item item={item} />
))}
</ol>
);
In React, you'll usually use the array map
method to display a list of items stored in an array.
But as soon as you add an item to the list in the above Code Sandbox, you will see a missing key warning displayed in the console.
This is because every time you're using the array map
method to loop over the items, you need to provide a unique key
prop. React uses this to identify which elements on the screen need to be re-rendered, so adding the key
prop helps you avoids unnecessary re-rendering in your app.
Here's an updated Code Sandbox Demo with the added key
prop.
Here, I've provided a unique key
prop to each element we're looping over like this:
<Item item={item} key={index} />
Now if you try to add some items, you won't get any warnings in the console.
Note: In the above code, as the elements not re-ordered or removed, using
index
askey
works fine. But if you're removing or changing the displayed elements' order, then you need to provide a unique key instead of usingindex
.
Don't Use Inline Functions the Wrong Way
Take a look at this Code Sandbox Demo.
Here, I've added some items to the state:
const [items, setItems] = useState(["one", "two"]);
and we're looping over them to display on the screen:
{items.map((item, index) => (
<li key={index}>
{item} <button onClick={handleRemoveItem(item)}>Remove</button>
</li>
))}
If you check the application, you will see that no items are displayed on the screen. Adding new items also doesn't work as you can see below:
This is because of the onClick
handler for the button:
<button onClick={handleRemoveItem(item)}>Remove</button>
Here, we're calling the handleRemoveItem
method when the user clicks on the button – but the way we're calling the method is wrong.
So if you don't need to pass any parameters, you use the following syntax:
<button onClick={handleRemoveItem}>Remove</button>
But later if you decide to pass some parameter to the function, you need to call the handler inside the inline function like this:
<button onClick={() => handleRemoveItem(item)}>Remove</button>
Most React developers forget to add an inline function and then it takes hours of debugging to understand why something does not work.
Here's an updated working Code Sandbox Demo.
Thanks for reading!
Starting with ES6, there are many useful additions to JavaScript like:
- ES6 Destructuring
- Import and Export Syntax
- Arrow functions
- Promises
- Async/await
- Optional chaining operator and a lot more.
You can learn everything about all the ES6+ features in detail in my Mastering Modern JavaScript book.
Check out free preview contents of the book here.
Also, you can check out my free Introduction to React Router course to learn React Router from scratch.
Want to stay up to date with regular content regarding JavaScript, React, Node.js? Follow me on LinkedIn.