Six Ways To Get Better At React

Up your React game with these tips

Malcolm Laing
Jun 25, 2020 · 7 min read
Image for post
Image for post
Photo by Priscilla Du Preez on Unsplash

Over the last six months, I have watched a junior React developer improve. When I think about what they knew then, and what they know now, I’m blown away. Their velocity, and their drive to learn and improve impressed me deeply.

So how did they do it? How did they go from someone who would message me for help before opening a pull request, to someone others go to for help? How did they go from asking for help to providing help? From a mentee to a mentor?

I asked them, and this is what they said.

1. ESLint + TypeScript

JavaScript is a loosely typed language. With JavaScript, we can solve the same problem in a thousand different ways. JavaScript on its own doesn’t stop us from writing buggy code, or from writing poorly performing code. Luckily for us, we can rely on two different tools to statically analyze our code: Typescript and ESLint.

By leveraging ESLint to statically analyze our code, we can spot problems before they make it into production. We can enforce standards, and keep our codebase maintainable.

For example, we can install the plugin eslint-plugin-react-hooks. This plugin will catch the following perfectly valid JavaScript code, and let us know that we are breaking the rule of hooks.

// 🔴 We're breaking the first rule by using a Hook in a condition
if (userName !== '') {
useEffect(function persistForm() {
localStorage.setItem('formData', userName);
});
}

We can also use the static type system in TypeScript to catch bugs before they make it into the codebase. TypeScript offers powerful and useful Intellisense, which makes it faster and easier to work with other components and libraries, as we can see their props as we code. It speeds up our refactoring, and it enforces good conventions like using Generics.

Becoming a strong TypeScript programmer not only makes you a better JavaScript programmer, but it also makes you write better React code.

2. Dive Deep Into Hooks

Since react hooks were introduced in February 2019, they have taken over the world of React by storm. While the React team encouraged us not to refactor our old code to make use of hooks, hooks are everywhere now.

If you want to become a better React programmer, the best thing you can do is take the time to fully understand hooks.

Need to perform side effects? useEffect is for your friend. Need to keep track of state between renders, and rerender when that state changes? useState has your back. Need to store and update a value between renders, without rendering? Or need to look up the height or width of a DOM element? useRef is your friend.

For example, let’s take a look at a naive use of useEffect. Let’s say we want to update the page title (a side effect), whenever we click a button.

useEffect(() => {
document.title = `You clicked ${count} times`;
}); // runs on every render

We can easily optimize our hook so that instead of running on every render, it only runs when the variable count changes. We do this by adding count to the dependency array.

useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes

You should be comfortable using the most common hooks, as well as creating your own hooks. You should also have a good understanding of when to use hooks like useEffect that lead to rerenders, and when no to.

3. Don’t Optimize Too Soon

This brings us to our next point. Too often I have seen junior React developers agonizing over making their code as performant as possible. useMemo and useCallback are the two most common hooks used for optimizing your React code. So when should you use them, and when should you not?

Let’s take a look at a simple component that accepts an array of candies as a prop. It filters this array and displays the name of each candy of type chocolate.

Some developers might feel the urge to write code like this. They might think to themselves, well I only want to update my list of chocolates when my candies change. But it results in hard to read code and more overhead.

const Chocolate = (props) => {
const chocolates = useMemo(
() => props.candies.filter((candy) => candy.type === "chocolate"),
[props.candies]
);
return (
<>
{chocolates.map((item) => (
<p>{item.name}</p>
))}
</>
);
};

Instead, I would urge you to write simple, clean code. There’s no reason to useMemo in cases like this. You should only useMemo or useCallback to memorize the result of expensive, computationally heavy operations.

Don’t just all useCallback and useMemo all over the place because you read about them in a Medium article. Don’t optimize everything, wait until you find a problem, and then solve it. Don’t solve problems that don’t exist.

4. Know When To Make A New Component

I have seen many new React developers mix business logic into what should be purely presentational components. In order to make your code as reusable as possible, it’s important to make your components as reusable as possible.

To achieve this, we should try to maintain a separation between presentational components, and components that contain logic. In the past, it was common to split your components between so-called “Containers” and “Components”. This has since fallen out of favour.

Let’s take a look at a component that fetches a list of items, and displays their information, all in one component.

const ListItems = () => {
const items = React.useState([]);
React.useEffect(() => {
async function fetchItems() {
await fetched = fetchItems();
setItems(fetched);
}
fetchItems();
});
return (
<>
{items.map((item) => (
<div className="item-container">
<img src={item.img} />
<div className="name">{item.name}</div>
<div className="author">{item.author}</div>
</div>
))}
</>
);
};

We might be tempted to follow the “Container” approach. Following that approach, we would end up with two components, like this.

const ListContainer = () => {
const items = React.useState([]);
React.useEffect(() => {
async function fetchItems() {
await fetched = fetchItems();
setItems(fetched);
}
fetchItems();
});
return <List items={items} />;
};
const List = (props) => {
return (
<>
{props.items.map((item) => (
<div className="item-container">
<img src={item.img} />
<div className="name">{item.name}</div>
<div className="author">{item.author}</div>
</div>
))}
</>
);
};

Instead, we should abstract away the purely presentational parts. We end up with two components, our List component, and our Item component.

const List = () => {
const items = React.useState([]);
React.useEffect(() => {
async function fetchItems() {
await fetched = fetchItems();
setItems(fetched);
}
fetchItems();
});
return (
<>
{items.map((item) => (
<Item item={item} />
))}
</>
);
};
const Item = ({ item }) => {
return (
<div className="item-container">
<img src={item.img} />
<div className="name">{item.name}</div>
<div className="author">{item.author}</div>
</div>
);
};

5. Concentrate On Testing

Testing is the single biggest thing that separates a junior developer from a senior. If you aren’t familiar with testing React applications, there is a lot of great material out there to get you up to speed.

Maybe you have made a few unit tests in the past, but you don’t have much experience writing integration tests for whole applications? Don’t fret, there’s tons of free material online to get you up to speed.

We even published a tutorial that walks you through testing a Full-Stack React application from start to finish.

6. When to use Global vs Local State

State management in React. There are so many different solutions out there. Redux, mobx, recoil, context API, etc. There are too many options out there to name.

Regardless of the state management solution, I often see junior React developers making is mixing up when they should use global state, versus local state. Unfortunately, there is no hard and fast rule that tells you when you should keep things in local versus global state.

  • Do other unrelated components in the application need access to this data? (example: username, display it in the navbar and on the welcome screen).
  • Should the data be persisted as you move between pages?
  • Is the same data being used in multiple components?

If the answer is yes to any of these questions, you may want to use global state. But don’t put the open state of your menu inside of the global state. Try to reason about needs to be shared across your application, and what can live inside of a local component.

So there you have it. Six ways that you can improve as a React developer.

When I think back to the code I wrote as a junior React developer, I remember one thing. I wrote overcomplicated and hard to follow code. As I’ve gained more experience, I have found that I write simpler code. Simpler code is always better. It’s easier to understand now, and it’s even easier to understand in six months when a bug pops up.

Can you think of some other ways to improve as a React developer? Let us know in the comments!

Frontend Digest

Anything and everything frontend. JavaScript, CSS and HTML.

By Frontend Digest

The latest and greatest in frontend development Take a look.

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

Malcolm Laing

Written by

JavaScript Consultant. Senior React developer. Still makes silly mistakes daily.

Frontend Digest

Anything and everything frontend. JavaScript, CSS and HTML.

Malcolm Laing

Written by

JavaScript Consultant. Senior React developer. Still makes silly mistakes daily.

Frontend Digest

Anything and everything frontend. JavaScript, CSS and HTML.