DEV Community

Pratham Srivastava
Pratham Srivastava

Posted on

✔5 Best Practices for Writing Cleaner and More Readable React Code

In the world of software development, code readability is paramount. We spend more time reading code than writing it, making it crucial to adopt practices that enhance clarity and maintainability. In this article, we'll explore five better React code practices that contribute to improved code readability.

1. Always Add Keys When Using Map

One common scenario in React involves mapping over arrays to render components dynamically. To enhance readability and optimize React's rendering performance, always include keys when using the map function.

// ❌ Not-so-good
{data.map(item => <MyComponent />)}

// ✅ BETTER
{data.map(item => <MyComponent key={item.id} />)}
Enter fullscreen mode Exit fullscreen mode

Adding unique keys helps React efficiently update and re-render components, providing a smoother user experience. 🔄

2. Use Callback Functions Instead of State Dependencies:

When working with the useCallback hook in React, it's a good practice to use callback functions for state updates instead of including the state variable as a dependency.

// ❌ Not-so-good
const decrement = useCallback(() => setCount(count - 1), [setCount, count])

// ✅ BETTER
const decrement = useCallback(() => setCount(prevCount => prevCount - 1), [])
Enter fullscreen mode Exit fullscreen mode

This practice avoids unnecessary dependencies in the dependency array and ensures that the correct state is captured when the callback is invoked. 🔄

3. Simplify Complex Conditionals and Exit Early:

To enhance code readability, simplify complex conditionals and exit early when possible. This not only reduces nesting but also makes the code more straightforward.

// 🙈 Not-so-good
if (loading) {
  return
} else if (error) {
  return
} else if (data) {
  return
} else {
  throw new Error('This should be impossible')
}

// ✅ BETTER
if (loading || error || data) {
  return
}

throw a new Error('This should be impossible')
Enter fullscreen mode Exit fullscreen mode

By breaking down complex conditionals and exiting early, you improve code readability and reduce cognitive load. 🚀

4. Use Short-Circuit Evaluation for Conditionals in JSX:

When rendering components conditionally in JSX, leverage short-circuit evaluation for cleaner and more concise code.

// Instead of
const sampleComponent = () => {
  return isTrue ? <YourComponent/> : null;
};

// Use short-circuit evaluation
const sampleComponent = () => {
  return isTrue && <YourComponent/>;
};
Enter fullscreen mode Exit fullscreen mode

Short-circuit evaluation allows you to express conditional rendering in a more concise manner, making your JSX more readable. 🌐

5. Destructure Props in Function Parameters:

When working with component props, destructure them directly in the function parameters. This not only enhances code readability but also provides a clear overview of the props being used.

// ❌ Not-so-good
const MyComponent = (props) => {
  const { prop1, prop2 } = props;
  // ...
};

// ✅ BETTER
const MyComponent = ({ prop1, prop2 }) => {
  // ...
};
Enter fullscreen mode Exit fullscreen mode

By destructuring props in the function parameters, you make the code more concise and immediately highlight the props utilized within the component. 🔍

Top comments (11)

Collapse
 
sunflowertoadtheorbiter profile image
SunflowerToadTheOrbiter • Edited

My opinion on #5: while making the code more concise, this approach makes the function signature less recognizable, especially when you start working with TypeScript (additional types for long lines).

Also i find the syntax to then be similar to the one beeing used for states in functional react programing:

function Bongo(props) {
  const { name, image } = props;
  const [isHappy, setIsHappy] = useState(true);
}
Enter fullscreen mode Exit fullscreen mode

Deconstructing in the function params may work ok for Javascript but i see this not beeing a best practice for typescript.

Collapse
 
bgibb95 profile image
Brendan

Thanks for this article :)

I don't agree with number 4 entirely though (Using && operator in JSX) because it can lead to bugs.

Here is more information:
crocoder.dev/blog/react-conditiona...

Collapse
 
prathamisonline profile image
Pratham Srivastava

Thanks for the additional info.

<div>{dodos.length && `dodos: ${dodos.map(() => '🦤').join(' ')}`}</div> 

//both will work 
<div>{dodos.length >0 && `dodos: ${dodos.map(() => '🦤').join(' ')}`}</div> 
<div>{!!dodos.length && `dodos: ${dodos.map(() => '🦤').join(' ')}`}</div> 
Enter fullscreen mode Exit fullscreen mode
Collapse
 
cupcake-monster profile image
Cupcakes • Edited

Hello. I have a question about #5. I see this being used in a lot of projects, but I have never used it in practice. My reasoning is that, when props are destructured in the parameters list, I am not able to console.log(props) from within the body of the component. This is something that I end up doing a lot while building projects. I am wondering if there is any benefit to destructuring props in the arguments list other than it's more concise?

Collapse
 
brense profile image
Rense Bakker

Destructuring early helps to prevent dependency on irrelevant props for the component's side effects and children. Wanting to log all the props seems strange though? Can you elaborate why you'd want to log the entire props object, instead of the specific props that you're interested in? If you don't trust which props are passed down to your component, something is wrong with the component's contract...

Collapse
 
cupcake-monster profile image
Cupcakes

Hi Rense,
Thank you for your reply. You asked:

Can you elaborate why you'd want to log the entire props object, instead of the specific props that you're interested in?

One of the most convincing and frequent reasons (in my experience) is to detect spelling mistakes. Lets say that a generic <Button> component is used as a leaf node in an app. This component is blue by default, but is may also appear as light grey when the disabled prop is set to true. This prop may also be explicitly set to true or not set at all.

While manually testing this app in a browser, I notice that it does not render as light grey when I expect it to. I'm pretty sure I did everything correctly. To test, I cab console.log(props) to see what was sent to the component. In this imaginary example, perhaps isDisabled was sent by mistake from one it the button's ancestors. I now know what to look for.

I've ran into many scenarios where it has been beneficial to see what data has been passed to a component.

If you don't trust which props are passed down to your component, something is wrong with the component's contract...

Totally. Being able to see what has been passed down helps me to determine what the issue is and points me in the right direction of how it may be fixed.

I'm still a bit confused as to how these two styles are different:

const MyComponent = (props) => {
  const { prop1, prop2 } = props
}

const MyComponent = ({ prop1, prop2 }) => {
}
Enter fullscreen mode Exit fullscreen mode

Are there performance or other benefits to be gained by destructuring in the parameter list rather than on the very first line?

Thread Thread
 
brense profile image
Rense Bakker

Hmm, but wouldnt it be better to use typescript or prop types to enforce your components contract with the outside world so this use case cannot happen at all? npmjs.com/package/prop-types

Performance wise eventually it doesn't matter if you destructure on the next line no, it's more of a code practice that people follow, to help make code easier/faster to read/understand.

Thread Thread
 
oadrian2 profile image
oadrian2

I would imagine using React's dev tools to be a more efficient way to get that prop information. You can then even see the cascade of all of the various prop drilling that led to those values.

Collapse
 
danialdene profile image
Danial Hakim

Actually destructuring will be more clean code, and also if we have a lot of props we dont need to use the parent name e.g

user {
name
age
gender
}

usually will use

name: user.name
age: user.age
gender: user.gender

with destructure

const {name, age, gender } = user

name: name
age: age
gender: gender

Collapse
 
amirvalipouri profile image
amir valipouri

Every react developer must know these rules

Collapse
 
sammiee profile image
sammie

Great!