DEV Community

loading...
Cover image for 7 Ways to Write Cleaner React Code Today

7 Ways to Write Cleaner React Code Today

reedbarger profile image Reed Barger Originally published at reedbarger.com ・7 min read

📣 This post originally appeared on ReedBarger.com.

As React developers, we all want to write cleaner code that is simpler and easier to read.

In this guide, I've put together seven of the top ways that you can start writing cleaner React code today to make building React projects and reviewing your code much easier.

In general, learning how to write cleaner React code will make you a more valuable and overall happier React developer, so let's jump right in!

Want the complete guide to writing clean React code from start to finish? Check out The React Bootcamp.

1. Make use of JSX shorthands

How do you pass a value of true to a given prop?

In the example below, we're using the prop showTitle to display the title of our app within a Navbar component.

// src/App.js

export default function App() {
  return (
    <main>
      <Navbar showTitle={true} />
    </main>
  );
}

function Navbar({ showTitle }) {
  return (
    <div>
      {showTitle && <h1>My Special App</h1>}
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Do we need to explicitly set show title to the Boolean true? We don't! A quick shorthand to remember is that any prop provided on a component has a default value of true.

So if we add the prop showTitle on Navbar, our title element will be shown:

// src/App.js

export default function App() {
  return (
    <main>
      <Navbar showTitle />
    </main>
  );
}

function Navbar({ showTitle }) {
  return (
    <div>
      {showTitle && <h1>My Special App</h1>} // title shown!
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Another useful shorthand to remember involves passing string props. When you're passing a prop value that's a string, you don't need to wrap it in curly braces.

If we are setting the title of our Navbar, with the title prop, we can just include its value in double quotes:

// src/App.js

export default function App() {
  return (
    <main>
      <Navbar title="My Special App" />
    </main>
  );
}

function Navbar({ title }) {
  return (
    <div>
      <h1>{title}</h1>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

2. Move unrelated code into a separate component

Arguably the easiest and most important way to write cleaner React code is to get good at abstracting our code into separate React component.

Let's look at the example below. What is our code doing?

Our app is displaying a Navbar component. We are iterating over an array of posts with .map() and displaying their title on the page.

// src/App.js

export default function App() {
  const posts = [
    {
      id: 1,
      title: "How to Build YouTube with React"
    },
    {
      id: 2,
      title: "How to Write Your First React Hook"
    }
  ];

  return (
    <main>
      <Navbar title="My Special App" />
      <ul>
        {posts.map(post => (
          <li key={post.id}>
            {post.title}
          </li>
        ))}
      </ul>
    </main>
  );
}

function Navbar({ title }) {
  return (
    <div>
      <h1>{title}</h1>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

How can we make this cleaner?

Why don't we abstract the code that we're looping over--our posts--and display them in a separate component, which we'll call FeaturedPosts.

Let's do that and take a look at the result:

// src/App.js

export default function App() {
 return (
    <main>
      <Navbar title="My Special App" />
      <FeaturedPosts />
    </main>
  );
}

function Navbar({ title }) {
  return (
    <div>
      <h1>{title}</h1>
    </div>
  );
}

function FeaturedPosts() {
  const posts = [
    {
      id: 1,
      title: "How to Build YouTube with React"
    },
    {
      id: 2,
      title: "How to Write Your First React Hook"
    }
  ];

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}
Enter fullscreen mode Exit fullscreen mode

As you can see, we can now just look at our App component and by reading the names of the components within it, Navbar and FeaturedPosts, we see exactly what our app is displaying.

3. Create separate files for each component

Going off of our previous example, we are including all of our components within a single file, the app.js file.

Similar to how we abstract code into separate components to make our app more readable, to make our application files more readable, we can put each component that we have into a separate file.

This, again, helps us separate concerns in our application, meaning that each file is responsible for just one component and there's no confusion where a component comes from if we want to reuse it across our app:

// src/App.js
import Navbar from './components/Navbar.js';
import FeaturedPosts from './components/FeaturedPosts.js';

export default function App() {
  return (
    <main>
      <Navbar title="My Special App" />
      <FeaturedPosts />
    </main>
  );
}
Enter fullscreen mode Exit fullscreen mode
// src/components/Navbar.js

export default function Navbar({ title }) {
  return (
    <div>
      <h1>{title}</h1>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode
// src/components/FeaturedPosts.js

export default function FeaturedPosts() {
  const posts = [
    {
      id: 1,
      title: "How to Build YouTube with React"
    },
    {
      id: 2,
      title: "How to Write Your First React Hook"
    }
  ];

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}
Enter fullscreen mode Exit fullscreen mode

Additionally, by including each individual component within its own file, we avoid one file becoming too bloated. We could easily see our app.js file becoming very large if we wanted to add all of our components into that file.

4. Move shared functionality into React hooks

Taking a look at our FeaturedPosts component, let's say instead of displaying static posts data, we want to fetch our post data from an API.

We might do so with the fetch API. You can see the result below for that:

// src/components/FeaturedPosts.js

import React from 'react';

export default function FeaturedPosts() {
  const [posts, setPosts] = React.useState([]);     

  React.useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/posts')
      .then(res => res.json())
      .then(data => setPosts(data));
  }, []);

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}
Enter fullscreen mode Exit fullscreen mode

However, what if we wanted to perform this request for data across multiple components?

Let's say in addition to a FeaturedPosts component we wanted to create a component called just Posts with the same data. We would have to copy the logic that we used to fetch our data and paste it within that component as well.

To avoid having to do that, why don't we just use a new React hook which we could call useFetchPosts:

// src/hooks/useFetchPosts.js

import React from 'react';

export default function useFetchPosts() {
  const [posts, setPosts] = React.useState([]);     

  React.useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/posts')
      .then(res => res.json())
      .then(data => setPosts(data));
  }, []);

  return posts;
}
Enter fullscreen mode Exit fullscreen mode

Once we've created this hook in a dedicated 'hooks' folder we can reuse it in whichever components we like, including our FeaturedPosts component:

// src/components/FeaturedPosts.js

import useFetchPosts from '../hooks/useFetchPosts.js';

export default function FeaturedPosts() {
  const posts = useFetchPosts()

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}
Enter fullscreen mode Exit fullscreen mode

5. Remove as much JavaScript from your JSX as possible

Another very helpful, but often neglected way to clean up our components is to remove as much JavaScript from our JSX as possible.

Let's take a look at the example below:

// src/components/FeaturedPosts.js

import useFetchPosts from '../hooks/useFetchPosts.js';

export default function FeaturedPosts() {
  const posts = useFetchPosts()

  return (
    <ul>
      {posts.map((post) => (
        <li onClick={event => {
          console.log(event.target, 'clicked!');
        }} key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}
Enter fullscreen mode Exit fullscreen mode

We're trying to handle a click event on one of our posts. You can see that our JSX becomes much harder to read. Given that our function is included as an inline function, it obscures the purpose of this component, as well as the its related functions.

What can we do to fix this? We can extract the inline function, connected to the onClick into a separate handler, which we can give a an appropriate name like handlePostClick.

Once we do, our JSX becomes readable once again:

// src/components/FeaturedPosts.js

import useFetchPosts from '../hooks/useFetchPosts.js';

export default function FeaturedPosts() {
  const posts = useFetchPosts()

  function handlePostClick(event) {
    console.log(event.target, 'clicked!');   
  }

  return (
    <ul>
      {posts.map((post) => (
        <li onClick={handlePostClick} key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}
Enter fullscreen mode Exit fullscreen mode

6. Format inline styles for less bloated code

A common pattern for React developers is to write inline styles in their JSX but once again, it makes our code harder to read and harder to write additional JSX:

// src/App.js

export default function App() {
  return (
    <main style={{ textAlign: 'center' }}>
      <Navbar title="My Special App" />
    </main>
  );
}

function Navbar({ title }) {
  return (
    <div style={{ marginTop: '20px' }}>
      <h1 style={{ fontWeight: 'bold' }}>{title}</h1>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

We want to apply this concept of separation of concerns to our JSX styles by moving our inline styles into a CSS stylesheet, which we can import into whatever component we like.

An alternative way to rewrite your inline styles is by organizing them into objects. You can see what such a pattern would look like below:

// src/App.js

export default function App() {
  const styles = {
    main: { textAlign: "center" }
  };

  return (
    <main style={styles.main}>
      <Navbar title="My Special App" />
    </main>
  );
}

function Navbar({ title }) {
  const styles = {
    div: { marginTop: "20px" },
    h1: { fontWeight: "bold" }
  };

  return (
    <div style={styles.div}>
      <h1 style={styles.h1}>{title}</h1>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

7. Reduce prop drilling with React context

Another essential pattern to employ for your React projects, especially if you have common properties that you want to reuse across your components, and you find yourself writing lots of duplicate props, is to use React Context.

For example, if we wanted to share user data across multiple components, instead of multiple repeat props (a pattern called props drilling), we could use the context feature that's built into the React library.

In our case, if we wanted to reuse user data across our Navbar and FeaturedPosts components, all we would need to do is wrap our entire app in a provider component.

Next, we can pass the user data down on the value prop and consume that context in our individual components with the help of the useContext hook:

// src/App.js

import React from "react";

const UserContext = React.createContext();

export default function App() {
  const user = { name: "Reed" };

  return (
    <UserContext.Provider value={user}>
      <main>
        <Navbar title="My Special App" />
        <FeaturedPosts />
      </main>
    </UserContext.Provider>
  );
}

// src/components/Navbar.js

function Navbar({ title }) {
  const user = React.useContext(UserContext);

  return (
    <div>
      <h1>{title}</h1>
      {user && <a href="/logout">Logout</a>}
    </div>
  );
}

// src/components/FeaturedPosts.js

function FeaturedPosts() {
  const posts = useFetchPosts();
  const user = React.useContext(UserContext);

  if (user) return null;

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

I hope you find this guide helpful as a resource to find ways to improve your own React code that is cleaner, easier to read, and ultimately more enjoyable to create your React projects.

Enjoy this post? Join The React Bootcamp

The React Bootcamp takes everything you should know about learning React and bundles it into one comprehensive package, including videos, cheatsheets, plus special bonuses.

Gain the insider information hundreds of developers have already used to master React, find their dream jobs, and take control of their future:

The React Bootcamp

Click here to be notified when it opens

Discussion (7)

pic
Editor guide
Collapse
thomasledoux1 profile image
Thomas Ledoux

Nice article! Maybe it would be good to include the shorthand for an "if/else" check in the first part? For example:

export default function App() {
  return (
    <main>
      <Navbar showTitle />
    </main>
  );
}

function Navbar({ showTitle }) {
  return (
    <div>
      {showTitle ? (<h1>My Special App</h1>) : (<h1>Default title</h1>)}  //default title is shown when showTitle is false
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode
Collapse
reedbarger profile image
Reed Barger Author

I would write your code snippet as follows, without having to write the h1 element twice. Cuts down on our code a bit:

export default function App() {
  return (
    <main>
      <Navbar showTitle />
    </main>
  );
}

function Navbar({ showTitle }) {
  return (
    <div>
      <h1>{showTitle ? "My Special App" : "Default title"}</h1>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode
Collapse
thomasledoux1 profile image
Thomas Ledoux

Oh yea, in this case that’s certainly possible! My code would be more useful when you have to use another element instead of the

:-)

Collapse
pengeszikra profile image
Peter Vivo • Edited

Maybe arrow function much more minimalist, special when component don't contain any JS code.

export const FooComponent = ({content, title, handleClick}) => (
  <section className="foo-component" onClick={handleClick}>
     <header>{title}<header>
     <p className="foo-component--content">{content}</p>
  </section>
);
Enter fullscreen mode Exit fullscreen mode
Collapse
manuthecoder profile image
ManuTheCoder

Very useful! Thank you. I'm actually learning react now, and thanks for the article!

Collapse
braydentw profile image
Brayden W ⚡️

Awesome tips - Thanks!

Some comments have been hidden by the post's author - find out more