React Anti-Patterns

February 20, 2019 โ€ข ๐Ÿ“š 9 min read โ€ข Tweet this post
Tires stacked in Pattern
Photo By Lane Smith
  • Am I using the right pattern?
  • What will my coworkers think of this?
  • Is this readable?

Everyone asks themselves these questions at some point when learning something new. I've been working with React for 3 1/2 years now and these are some patterns that have come back to bite me.


You should watch out for code that you can't understand easily, write readable code. Testable code is usually easier to read, so write tests! ๐Ÿงช

Shoutout to react-testing-library

Inheritance ๐Ÿ‘จโ€๐Ÿ‘ง

I first started writing React after reading a book on design patterns, and the first chapter was on Inheritance.

Headfirst Design Patterns Book

Great book, worth the read ๐Ÿ‘๐Ÿผ

The basics of inheritance are you have a class that can inherit the behavior of another class. Similar to how we inherit traits from our parents.

One of my first challenges was I had two components that needed the same data fetching behavior. And what came next was some of the worst code I have EVER written. I broke the number one React rule, I made a component base class ๐Ÿ™ˆ

It looked something like this:

1class Base extends React.Component {
2 componentDidMount() {
3 apiCall(this.props.type).then((data) => {
4 this.setState({ data });
5 });
6 }
8 render() {
9 throw new Error("SHOULD NEVER GET HERE");
10 }
13class Widget extends Base {
14 render() {
15 if (!this.state.data) return null;
17 return <div>{this.state.data.title}</div>;
18 }

This is bad. Don't ever throw inside render.

The idea was that Widget extends another component to save some code duplication. Don't use the extends keyword to inherit other React components. The funny thing is, React has explicit warnings against this! Read the docs people.

Prop spreading ๐Ÿ’”

I'm pretty sure everyone runs into this problem in React. I call it Prop Madness. Here is an example:

1function Outer({ data, onHover, onClick, onSaveInner }) {
2 return (
3 <Inner
4 title={data.title}
5 date={data.date}
6 isTesting={data.isTesting}
7 text={data.text}
8 actionButtonTitle={data.actionButtonTitle}
9 onHover={onHover}
10 onClick={onClick}
11 onSaveInner={onSaveInner}
12 />
13 );
16function Inner({ title, date, isTesting, onHover, onClick }) {
17 // Do stuff ...

You can mask the problem like this:

1function Outer({ data, onHover, onClick, onSaveInner }) {
2 return (
3 <Inner
4 {...data}
5 onHover={onHover}
6 onClick={onClick}
7 onSaveInner={onSaveInner}
8 />
9 );
12function Inner({ title, date, isTesting, onHover, onClick }) {
13 // Do stuff ...

Problem solved! Right?


We haven't really solved it. Now any extra properties on the data object get passed to the <Inner /> component when they don't need to! And what happens when some of those props become optional? When the <Inner /> component wants to rename one of those props?

Also notice how the <Outer /> component doesn't actually use any of the props, it just passes them along!

This approach couples the two components together, you may as well inline the <Inner /> component inside the <Outer />

React created a built-in approach to solving this problem. It's called Context.

Context can solve this problem quite nicely, and I recommend learning the API. However, if you use something like Redux, Apollo, Relay, MobX, or anything similar, keep in mind the next Anti-pattern.

Smart and Dumb components ๐ŸŽญ

Too often I see code that is over-abstracted and split up into pieces that are too small. Not just with React either. Have you ever seen a generic /utils folder that holds all the business logic and each "utility" is only used in one other place? It's misdirection (not abstraction), and it hurts code readability.

Our Prophet, Dan Abramov, recently made an addendum to his post on Presentational vs Container Components, stating that separation like this can be harmful when taken too seriously.

I live by the following mantra:

A component is a component

Simple right? The idea is that we don't need to separate concerns and make components focused on styles ๐Ÿ’… or data ๐Ÿ“ˆ. A component is a component, and that means it doesn't matter if it has css, or makes api calls. Prop Madness can occur when trying to separate components by what they do instead of what they are.

Don't over-abstract your components. Don't focus on DRY code too much, and favor code readability over patterns and reuse.

My favorite quote about programming in general:

"Make it work, Make it right, Make it fast" - Kent Beck

Too many files ๐Ÿ—‚

People, It's O.K. to put more than one component in a single file. I'm not sure what started this trend, but I've seen projects where there is a file per component or even per function ๐Ÿ˜ฑ.

Co-location is perfectly valid if you don't need to reuse the code elsewhere.

Take the following NavBar component for example:

1import React from "react";
2import axios from "axios";
3import styled from "styled-components";
5// Styled-components are my favorite ๐Ÿ˜Š๐Ÿ’…
6const Header = styled.h1`
7 background-color: #dc8b22;
8 font-size: 1.5rem;
9 text-decoration: underline;
12const Result = styled.div`
13 border-bottom: 2px solid orange;
16// I also love Axios!
17function apiCall(keyword) {
18 return axios.get(`/api/search?query=${keyword}`);
21export function NavBar() {
22 const [keyword, setKeyword] = useState("");
23 const [results, setResults] = useState(null);
25 function handleChange(event) {
26 setKeyword(event.target.value);
27 }
29 function search(event) {
30 event.preventDefault();
32 apiCall(keyword).then((data) => {
33 setResults(data.results);
34 });
35 }
37 return (
38 <header>
39 <form onSubmit={search}>
40 <input placeholder="Search" onChange={handleChange} />
41 </form>
42 {results.map((result) => (
43 <div key={result.id}>{result.value}</div>
44 ))}
45 </header>
46 );

This code is completely arbitrary, and I'm leaving quite a bit out.

Notice how it combines styles, data loading, and regular markup? Especially notice how this file encapsulates all the logic around the NavBar search? We should optimize our code for readability. In most cases having 3 files open to understand how a nav bar gets rendered is not readable.

Lastly... ๐Ÿค”

There are no anti-patterns!

Yeah, kinda boring conclusion here. I think the reason I've come to love React is the un-opinionated stance it takes. Do what makes sense and follow good principles of programming.

  • ๐Ÿงช Write tests
  • โ™ป๏ธ Always be refactoring
  • ๐Ÿ“š Optimize for readability

React is doing something we have never seen before, it is outlasting the Javascript library lifecycle. I'm extremely Bullish on React and I can't wait to see where we take it the next 5 years ๐Ÿ‘๐Ÿผ

About the Author

Hi ๐Ÿ‘‹ I'm Tyler. I'm a software engineer with a passion for learning new things. I love solving hard problems and simplifying them down to their pieces. Presently residing in Utah with my two girls and beautiful wife.

Buy me a coffee