5 React Component Best Practices You Should Know
Destructure props, named components, and more
React is meant to be an incredibly flexible software library, with no clear best practice when it comes to application structure or design. However, there are still some best practices and general rules that developers can use to write better React code.
Software architecture is meant to be productive and flexible for developers. The goal of good software is to keep the codebase maintainable and modular if any modifications or additions are needed.
I’ve put together some of the best practices I’ve picked for writing good React code, ones that have proven to be effective in applications large and small.
However, remember that these aren’t rules, these are opinions on what I’ve found the best practices are for writing good React code.
We’ll be divvying this up into a couple of sections and parts to make it easily digestible.
Components
We’ll be starting off talking about components and their structure.
Name components
Always name your React components. It makes it easier to read error stacks, use React dev tools, and search through a large code base.
It also helps autocomplete find the component you want to use!
// This is an unnamed component. Don't do this
export default () => <div>...</div>// This is a named component :)
export default function Card() { return <div>...</div> )
Write consistently organized components
Whatever style you choose to write components in, be sure it’s consistent throughout the entire code base. This means organization, like where you put your helper functions or the export, or function
syntax (like I did above) versus lambda functions. If the code looks and feels the same for every file, it makes every developer's life easier and more productive.
Separate constants and helpers into different files
My objective when writing React components is to keep each file under 200 lines. This means moving helper
functions into a separate component.utils.ts
file and constants into acomponent.constants.ts
file to make the component smaller and easier to read.
This is particularly effective when working with large state objects:
With this structure, it becomes much easier to understand even really complex components since they’re modular and broken into bite-size chunks.
Destructure props
Most React components are basic functions. They take in some props and return markup. The majority of the time, you use the arguments as passed in directly, so it makes sense to destructure props
so it’s not repeated everywhere.
Unless your component has managed states, it almost always makes sense to break down function parameters into individual keys:
Don’t pass a ton of props in
Complex components are harder to read and maintain. If you’re passing in a lot of props, really consider whether or not they can be broken down into more pieces. The number of props passed in is usually correlated to how much the component is doing.
If I have above six props being passed in, I normally know there’s some way to break down the component into smaller chunks. In some cases, like inputs, it’s OK to have a large number of props (they require a lot of values); otherwise, extract and modularize.
Avoid nesting render functions
This is my least favorite practice to see in the code I review. When extracting markup and logic from a component, don’t create a function living inside another component. Nesting components is almost always a bad idea and makes code hard to read.
Move the new component to its own files and rely on props rather than using a globally nested state.
Conditional rendering practices
There are a couple of great ways to do conditional rendering. Short circuit operators are a very short and easy way to do conditional rendering:
Here’s a great Stack Overflow post on short circuit operators that explains some more ways you can use these to write cleaner code.
Assign default props when destructuring
When using default props, you can use the defaultProps
property on a component, but don’t. This makes the component harder to read since the values aren’t declared where the keys are defined.
I prefer assigning default values when destructuring the props. It also makes it easier to read the code from top to bottom without having to jump around to find the default props, keeping the definitions and values together.
Prefer passing objects
One great way to limit the number of props passed is to pass an object instead of a set of primitive values. For example, rather than passing each aspect of a user, you can group them together. Down the road, if the user gains extra data, this function won’t have to be modified to accommodate that.
Move lists into separate components
One of the most common operations in React is looping through a list to generate components using a map
function. However, in components, this can lead to some messy code: the additional markup, indentation, and Javascript, none of which helps with readability.
When you need to map over elements, extract them into their own listing component. The parent component doesn’t need to know about the details if it’s only displaying the list, and this makes the parent a lot easier to read.
However, if a component's main responsibility is to display a list, keep it. There should only be a single mapping per component. If there are multiple, then they should all be extracted to their own components.
Conclusion
Remember that these are just suggestions, and the best practice is the one that works best for your team. In the next part, we’ll be talking about best practices for state management.