As React developers, we all want to write cleaner, easier to read code.

In this guide, I’ve summarized the seven most important ways you can start writing cleaner React code today, making it easier to build React projects and review your code.

In general, learning how to write clearer React code will make you a more valuable and happier React developer, so let’s get started!

1. Use the JSX abbreviation

How to pass the value of true to a given prop?

In the example below, we use the showTitle prop to display the title of our application in the navigation 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>)}Copy the code

Do we need to explicitly set showTitle to true? No! A simple way to remember is that any prop provided on a component has a default value of true.

So, if we add showTitle prop to the navigation bar, our title element will show:

// 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>)}Copy the code

Another useful shorthand method to remember is passing the string prop. When you pass a prop value for a string, you do not need to wrap it in curly braces.

If we want to set the title of the navigation bar, using title prop, we just need to 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>)}Copy the code

2. Move unrelated code into a separate component

Without a doubt, the simplest and most important way to write cleaner React code is to abstract it into a separate React component.

Let’s look at the following example. What is our code doing?

Our application is displaying a navigation bar component. We use.map() to walk through an array of posts and display their titles on the page.

// src/App.js

export default function App() {
  const posts = [
    {
      id: 1.title: "How to Build App 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>
  );
}
Copy the code

How can we make it cleaner?

Why don’t we abstract the code we’re looping — our Posts — and display them in a separate component, which we’ll call FeaturedPost.

Let’s take a look at the results:

// 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 App 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>
  );
}
Copy the code

As you can see, we just need to look at our App component now. By reading the names of components, navigation bars, and FeaturedPosts, we can see exactly what our application is showing.

3. Create separate files for each component

In the previous example, we included all the components in a single file app.js.

Just as we abstracted our code into separate components to make our application more readable and our application files more readable, we can put each component in a separate file.

Again, this helps us separate concerns in our application. This means that each file is responsible for only one component, and if we want to reuse it throughout the application, there is no confusion about where the component came from:

// 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>
  );
}
Copy the code
// src/components/Navbar.js

export default function Navbar({ title }) {
  return (
    <div>
      <h1>{title}</h1>
    </div>
  );
}
Copy the code
// 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>
  );
}
Copy the code

In addition, by including each individual component in our own file, we can prevent a file from becoming too bloated. If we wanted to add all the components to the app.js file, we could easily see the file become very large.

4. Move public functions to React Hooks

Looking at our FeaturedPosts component, instead of displaying static post data, we want to get the post data from the API.

We can use the FETCH API. You can see the results below:

// src/components/FeaturedPosts.js

import React from 'react';

export default function FeaturedPosts() {
  const [posts, setPosts] = React.useState([]);  	
    
  React.useEffect(() = > {
    fetch('https://example.com/posts')
      .then(res= > res.json())
      .then(data= >setPosts(data)); } []);return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}
Copy the code

But what if we want to execute this data request across multiple components?

Let’s say that in addition to the FeaturedPosts component, we want to create a component called Just Posts that has the same data. We must copy the logic used to get the data and paste it into the component.

To avoid this, why don’t we use a new React Hooks which we can call useFetchPosts:

// src/hooks/useFetchPosts.js

import React from 'react';

export default function useFetchPosts() {
  const [posts, setPosts] = React.useState([]);  	
    
  React.useEffect(() = > {
    fetch('https://example.com/posts')
      .then(res= > res.json())
      .then(data= >setPosts(data)); } []);return posts;
}
Copy the code

Once we’ve created this hook in a special “hooks” folder, we can reuse it in any component we like, including the 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>
  );
}
Copy the code

5. Remove as much JavaScript as possible from JSX

Another very useful but often overlooked way to clean up components is to remove JavaScript from JSX whenever possible.

Let’s look at the following example:

// 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>
  );
}
Copy the code

We are dealing with a click event on one of our posts. As you can see, our JSX has become more difficult to read. Because our function is included as an inline function, it obscures the purpose of this component and its related functions.

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

Once we do this, our JSX becomes readable 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>
  );
}
Copy the code

Format inline styles to reduce code bloat

A common pattern for React developers is to write inline styles in JSX. But again, this 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>)}Copy the code

We want to apply the concept of separation of concerns to JSX styles by moving inline styles into CSS stylesheets, which we can import into any component we want.

Another way to override inline styles is to organize them into objects. You can see that the pattern looks like this:

// 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>
  );
}
Copy the code

7. Use React Context to reduce prop Drilling

Another basic pattern for React projects is to use React Context(especially if you have some common properties that you want to reuse in your components, and you find yourself writing a lot of duplicate prop).

For example, if we want to share user data across multiple components, rather than multiple duplicate prop(a pattern called Props Drilling), we can use the context feature built into the React library.

In our example, if we wanted to reuse user data in the Navbar and FeaturedPosts components, we simply packaged the entire application into the Provider component.

Next, we can pass user data to a Value prop and, with the help of useContext hooks, use this context in various components:

// 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>
  );
}

Copy the code

conclusion

I hope this guide will be useful as you try to improve your own React code to make it clearer, easier to read, and ultimately more enjoyable to create your React projects.