This page looks best with JavaScript enabled

React antipatterns to avoid

 ·  ☕ 5 min read  ·  ✍️ Iskander Samatov

React Antipatterns


Here are some of the antipatterns most commonly seen in React applications and how to fix them. These antipatterns will make your codebase a nightmare to work with if you’re don’t learn to recognize and prevent them at their early stages.

Putting everything in Redux

Redux is awesome. It optimizes performance behind the scenes and lets us easily tap into the global state of the application.

The problem is that once new developers learn Redux, they start using it like a magic wand to solve all of their issues.
There are several drawbacks with this approach:

  • You are code loses intent. If everything is in Redux, it’s not clear if your code is supposed to have local or global scope. It’s trickier to make changes because you’re less confident about the parts of the app that will be affected.
  • Performance degrades when you use Redux for frequent events, like tracking form input. Since Redux affects the global state of the app, it is guaranteed to cause more re-renders.

The rule of thumb: Only use Redux for truly global data, like user session or app theme. For anything else, I like to create contexts for specific parts of the app instead.

Storing everything as a state

Another issue that new developers run into is under-utilizing the concept of derived state .

A lot of variables can be computed on the fly. For example, say you have an array of checkbox items. You don’t need to store checkedCount in the state. You can derive checkedCount by going through the array of items and filtering the checked ones on each render.

The rule of thumb: Before storing a variable in the state, ask yourself: “Can I somehow derive this variable based on other data I’m already storing?"

Passing props using spread operator everywhere

I’ve seen this trick used a lot in React applications.

You pass props to a child component using {...props}. It looks neat, and you might think you’re making your code more concise. But the truth is that over time your code will be less predictable and harder to understand.

When you start passing props using spread operator everywhere, it’s not immediately clear which props your child components actually need. Refactoring becomes almost impossible. Even small refactoring efforts will open up a can of worms. Plus it’s much harder to track bugs in your component tree.

The rule of thumb: Generally avoid passing props using the spread operator. One time when it’s justified is when writing a container component or HOC that renders and enhances its children.

Declaring components inside of components

Declaring component inside of another one looks like this:

ComponentInComponent

Writing components inside of their parents is a bad idea for two reasons:

  • Your code becomes tightly coupled. Your inner component becomes dependent on the closure scope of its parent.
  • Performance degrades. The parent component will re-create the declaration function of the child component on each render.

The rule of thumb: Avoid declaring components inside their parents.

Passing too much information to components

It’s good to be stingy with how much you’re letting your components know about. Try to keep the separation between smart and presentational components in mind when deciding how much data to pass.

Presentational components are components that solely output HTML. They do not hold state and are not handling any behavioral logic.

Smart components usually handle state and provide data and behavior to presentational components by making API requests, mutating redux, etc.

With presentational components, you should only pass data necessary for it to render. Presentational components shouldn’t decide whether to render their content. That logic should be handled by the smart components instead.

For example, take a look at this code:

Presentational Component  wrong

When you inspect the parent component, it’s not clear that our child component has conditional rendering logic. We can clarify this code by resurfacing the conditional logic and letting our parent component decide whether to render its child.

Presentational component correct

When possible, pass only primitives to presentational components. Doing so simplifies optimizing their performance later on. Say you’re passing the whole user object like so:

Presentation component whole object

You could instead pass the user’s first name, last name, and date:

Presentational component primitives

This makes it easier to reduce the number of re-renders using React.memo. The reason is that React compares object props based on the reference, while primitives are compared based on value.

To summarize, here are the problems with passing too much information to components:

  • Harder to distinguish between smart and presentational components. The primary logic of your application should be handled by smart components, while presentational ones solely output HTML.
  • Performance worsens. When you pass too many props to the component, it will re-render each time those props change, resulting in redundant re-renders.

Overoptimizing performance

Sometimes developers start optimizing their code before there’s any real issue. That’s a bad practice for two simple reasons:

  • Complicated and over-engineered code. Trying to solve the problem before there is one is the surest way to overcomplicate your code.
  • Wasted time. You could be building out new features and solving the problems that matter instead.

From my experience, intelligently separating smart and presentational components solves ~90% of the performance issues in React applications.

Huge component trees

Last but not least is large component trees.

Usually, this problem arises when you don’t take time to properly separate the logical and presentational pieces of your code.

For example, take a look at this component:

LargeTree

Yuck right? It’s very hard to decipher what’s going on here. We have several areas for improvement:

  • Refactor long conditional statements into separate variables.
  • Separate pieces of the tree into smaller presentational components.
  • Move the arrow function handlers out of the component tree.

Let’s apply these and see what the component looks like now:

Large Tree refactored

This component tree looks a lot better.

The rule of thumb: Keep component trees clean so that it’s easier to see what the component is supposed to be rendering and when.

Conclusion

In this post, we covered React antipatterns and how we can avoid them. By avoiding these antipatterns from the get-go, you won’t need to spend much time refactoring your code in the future. Check out my post here to learn more tips for writing clean React code .

If you’d like to get more web development, React and TypeScript tips consider following me on Twitter, where I share things as I learn them.
Happy coding!

Share on

Software Development Tutorials
WRITTEN BY
Iskander Samatov
The best up-to-date tutorials on React, JavaScript and web development.