React has quickly become the most popular front-end framework in the tech world, used by big tech companies such as Facebook, Netflix, Airbnb, and many more. React developers are in high demand, and the demand continues to grow.
Today, we’ll explore the top 10 mistakes React developers make -- and how to fix them.
We’ll cover:
- Not creating enough components
- Modifying the state directly
- Passing a number as a string when passing props
- Not using key on a listing component
- Forgetting that setState is asynchronous
- Using Redux too much
- Creating and using God components
- Not following the ReactJS folder structure
- Sending props as strings (instead of numbers)
- Forgetting to start a component name with a capital letter
- What to learn next
1. Not creating enough components
A common mistake that React developers make is that they don’t create enough components. With React, you’re able to create large components that execute many tasks, but it’s better to keep components small, with one component corresponding to one function. Not only does it save you time, but it also helps you with debugging since you know which components are associated with any errors that may arise.
Let’s take a look at an example of the TodoList
component:
// ./components/TodoList.js
import React from 'react';
import { useTodoList } from '../hooks/useTodoList';
import { useQuery } from '../hooks/useQuery';
import TodoItem from './TodoItem';
import NewTodo from './NewTodo';
const TodoList = () => {
const { getQuery, setQuery } = useQuery();
const todos = useTodoList();
return (
<div>
<ul>
{todos.map(({ id, title, completed }) => (
<TodoItem key={id} id={id} title={title} completed={completed} />
))}
<NewTodo />
</ul>
<div>
Highlight Query for incomplete items:
<input value={getQuery()} onChange={e => setQuery(e.target.value)} />
</div>
</div>
);
};
export default TodoList;
2. Modifying the state directly
In React, state should be immutable. If you modify the state directly, it’ll cause performance issues that are difficult to fix.
Let’s look at an example:
const modifyPetsList = (element, id) => {
petsList[id].checked = element.target.checked;
setPetsList(petsList);
};
You want to update the checked key of an object in an array based on the state of a checkbox, but you have a problem. React can’t observe and trigger re-rendering because the object is being changed with the same reference.
To fix this, you can either use the setState()
method or the useState()
hook. Either of these methods will ensure that your changes are acknowledged by React and your DOM is correctly re-rendered.
Let’s rewrite the previous example and use the useState()
method.
Note: You could also use
map()
andspread syntax
to avoid mutating other state values.
const modifyPetsList = (element, id) => {
const { checked } = element.target;
setpetsList((pets) => {
return pets.map((pet, index) => {
if (id === index) {
pet = { ...pet, checked };
}
return pet;
});
});
};
3. Passing a number as a string when passing props
Passing a number as a string when passing props can lead to issues in a React program.
Let’s start with an example:
class Arrival extends React.Component {
render() {
return (
<h1>
Hi! You arrived {this.props.position === 1 ? "first!" : "last!"} .
</h1>
);
}
}
In this example, the component expects the position as a prop and declares that the position should be a number. Since you’re making a strict comparison, anything that’s not a number or not exactly equal to 1 would trigger the second expression and print “last!”.
To fix this, you should insert curly brackets around the input like this:
const element = <Arrival position={1} />;
4. Not using key
on a listing component
Let’s say you need to render a list of items and your code looks something like this:
const lists = ['cat', 'dog', 'fish’];
render() {
return (
<ul>
{lists.map(listNo =>
<li>{listNo}</li>)}
</ul>
);
}
If you’re working with a smaller app, this could work. But when working with large lists, you’ll run into rendering problems when wanting to modify or delete an item from the list.
React tracks all of the list elements on the Document Object Model (DOM). React wouldn’t know what has changed in your list without this record.
To fix this, you need to add keys to all of your list elements. Keys give each element a unique identity, which helps React determine which items have been added, removed, modified, etc.
Here’s how to do this:
<ul>
{lists.map(listNo =>
<li key={listNo}>{listNo}</li>)}
</ul>
5. Forgetting that setState is asynchronous
It’s easy to forget that the state in React is asynchronous. It’s something that even the most seasoned React developers forget.
Being asynchronous means that any modifications you make don’t take effect immediately (and may take effect on the next render). React automatically batches update calls to improve performance. If you access a state value right after setting it, you might not get the most accurate result.
Let’s look at an example:
handlePetsUpdate = (petCount) => {
this.setState({ petCount });
this.props.callback(this.state.petCount); // Old value
};
You can fix this by giving an optional second parameter to setState()
, which will act as a callback function. The callback function will be called right after you update the state with your change.
handlePetsUpdate = (petCount) => {
this.setState({ petCount }, () => {
this.props.callback(this.state.petCount); // Updated value
});
};
Note: The same thing is true for
useState()
, except they don’t have a similar callback argument tosetState()
. Instead, you would use theuseEffect()
hook to get the same result.
6. Using Redux too much
With bigger React apps, many developers use Redux to manage global state. While Redux is useful, you don’t need to use it to manage every state in your apps.
If you have an app that doesn’t have any parallel-level components that need to exchange information, you have no need to add an extra library to your project. It’s recommended to use a local state method or useState
over Redux when you use a form component and want to check the state of a check button every time it’s accessed.
7. Creating and using God components
God components are monolithic and not reusable. They’re referred to as an “anti-pattern” in React. You shouldn’t build an entire page with all of your UI elements crammed into one component.
You should instead take the time to outline the different interconnected parts of your app and make them into their own components. When you separate components this way, all parts of your app are easier to maintain and restructure when needed.
8. Not following the ReactJS folder structure
The projects you create aren’t just made for current development. They most likely will need to be maintained or manipulated in the future. Folder structure is very important when considering future possibilities for a project.
Let’s take a look at a standard folder structure followed by the ReactJS community:
When navigating into any existing projects, it’s useful to have separate places for containers, assets, and components. It’s also useful to follow naming conventions to help with readability and organization. This helps you easily identify the purpose of any code written in your projects.
9. Sending props as strings (instead of numbers)
React developers with experience writing a lot of HTML find it natural to write something like this:
<MyComponent value=”4” />
This value prop will actually be sent to MyComponent as a string. If you do need it as a number, you can fix this issue by using something like the parseInt()
function or inserting curly brackets instead of quotation marks.
<MyComponent value={4} />
10. Forgetting to start a component name with a capital letter
Forgetting to start component names with capital letters is a small mistake that’s very easy to make. In JSX, a component that begins with a lowercase letter compiles down to an HTML element.
Let’s say you wrote something like this:
class demoComponentName extends React.Component {
}
This will cause an error that tells you that if you meant to render a React component, you need to start its name with an uppercase letter.
This mistake has an easy fix, which is starting component names with capital letters like this:
class DemoComponentName extends React.Component {
}
What to learn next
Now that we’ve explored the top ten mistakes React developers make, it’s time to start working with React and applying the skills you learned here today. React developers are in high demand, so adding React to your skillset is a wise career investment.
Some recommended concepts to work with next are:
- Libraries in React
- Initializing Firebase in React
- App development with Global State in React
- Etc.
To get hands-on experience with these concepts and more, check out Educative’s learning path, React for Front-End Developers. This learning path is perfect for you if you already have experience working with JavaScript and are ready to add React to your skillset. You’ll cover everything from the fundamentals of React to making use of design patterns when creating apps in React, all with in-browser coding exercises.
Happy learning!