React Cheatsheet – 9 Common HTML Rendering Cases You Should Know

As a full-stack developer, you know that a significant portion of your React development time is spent on writing the UI – assembling components, passing data from parents to children, conditionally rendering elements, and iterating over lists. React‘s declarative JSX syntax makes this process intuitive by allowing you to describe what your component‘s HTML output should look like for any given state.

While JSX might feel magical at first, it‘s important to understand that under the hood, each JSX element is transpiled into a plain JavaScript React.createElement() call. For example, this code:

const element = ;

Becomes this:

const element = React.createElement(
  ‘h1‘,
  null,
  ‘Hello, world!‘
);

Understanding this key piece of how JSX works will give you a better mental model for the rendering patterns we‘re about to dive into. Let‘s look at 9 of the most common patterns for rendering HTML in React components, along with real-world examples and best practices from a full-stack developer‘s perspective.

1. Outputting Data into HTML

The most fundamental pattern in React rendering is outputting a dynamic value into your HTML. This is achieved using curly braces {} in your JSX:

function Greeting({ name }) {
  return ;
}

Here, the name prop is being interpolated into the h1 content. You can put any valid JavaScript expression inside the curly braces, including function calls and arithmetic operations:

function FileSize({ bytes }) {
  return (
    <p>
      {bytes} bytes = {(bytes / 1024).toFixed(2)} KB
    </p>
  );
}

This allows for flexible, dynamic rendering without the need for manual DOM manipulation.

2. Adding Class Attributes

In HTML, you use the class attribute to apply CSS classes to an element. However, because class is a reserved keyword in JavaScript, JSX uses className instead:

<div className="card">
  {/* content */}
</div>

This is one of several special attributes in JSX that differ from their HTML counterparts. Others include htmlFor (instead of for on <label> elements) and tabIndex (instead of tabindex). Remembering these differences can trip up even experienced developers, so it‘s good to keep a reference like this handy.

3. Outputting Data into HTML Attributes

Interpolating dynamic values into HTML attributes follows the same curly brace syntax as content:

function UserLink({ user }) {
  return (
    <a href={`/users/${user.id}`} title={user.name}>
      {user.name}
    </a>
  );
}

You can even spread an entire object into a component as props, which is useful for passing down multiple attributes at once:

function Button({ isDisabled, ...props }) {
  return (
    <button disabled={isDisabled} {...props}>
      {props.children}
    </button>
  );
}

In this example, any additional props passed to the Button component (like onClick, className, etc.) will be spread onto the rendered <button> element.

4. Rendering Raw HTML

There are scenarios where you might need to render raw HTML that comes from an external source, like user-generated content from a CMS. To do this in React, you use the dangerouslySetInnerHTML prop:

function UserComment({ comment }) {
  return (
    <div
      className="comment"
      dangerouslySetInnerHTML={{ __html: comment.body }}
    />
  );
}

As the name implies, this prop can be dangerous if misused. If the HTML being interpolated isn‘t properly sanitized, it could open your application to cross-site scripting (XSS) attacks.

To mitigate this risk, always sanitize any user-provided HTML before rendering it with dangerouslySetInnerHTML. One popular library for this is DOMPurify:

import DOMPurify from ‘dompurify‘;

function SafeUserComment({ comment }) {
  const sanitizedBody = DOMPurify.sanitize(comment.body);

  return (
    <div
      className="comment"
      dangerouslySetInnerHTML={{ __html: sanitizedBody }}
    />
  );
}

By running the HTML through DOMPurify before rendering, we ensure that any malicious scripts or tags have been removed.

5. Iterating Over Data Sets

Rendering lists of data is a common task in any UI development. In React, you can use the built-in map function to iterate over an array and render a component for each item:

function ShoppingList({ items }) {
  return (
    <ul>
      {items.map(item => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
}

Notice the key prop on the <li> element. Whenever you‘re rendering an array of elements, each one needs a unique key to help React efficiently update the DOM. Using an ID from the data is ideal, as it ensures the key will remain consistent even if the order of items changes.

// ❌ Avoid: using array index as key
{items.map((item, index) => (
  <li key={index}>{item.name}</li>
)}

// ✅ Prefer: unique ID from the data
{items.map(item => (
  <li key={item.id}>{item.name}</li>
)}

6. Iterating Over Data Sets with Index

While using array indexes as keys is generally discouraged, there are cases where it‘s acceptable. For example, if you have a static list of items that will never reorder, using the index as a key is fine:

function NavigationMenu() {
  const menuItems = [‘Home‘, ‘About‘, ‘Contact‘];

  return (
    <ul>
      {menuItems.map((item, index) => (
        <li key={index}>
          <a href={`/${item.toLowerCase()}`}>{item}</a>
        </li>
      ))}
    </ul>
  );
}

However, if your list is dynamic or the order of items can change, stick with unique IDs for keys. Using indexes in those cases can lead to subtle bugs and performance issues.

7. Conditional Rendering

Conditional rendering is a fundamental concept in React that allows you to display different content based on certain conditions. The most basic way to achieve this is with an if statement and the && operator:

function SubscriptionButton({ isSubscribed }) {
  return (
    <>
      <button>
        {isSubscribed ? ‘Unsubscribe‘ : ‘Subscribe‘}
      </button>

      {isSubscribed && (
        <p>Thanks for subscribing!</p>
      )}
    </>
  );
}

In this example, the button text changes based on the isSubscribed prop. Additionally, the "Thanks for subscribing" message is only rendered if isSubscribed is truthy.

You can also use variables to conditionally assign JSX to be rendered later:

function Greeting({ name }) {
  let greeting;

  if (name) {
    greeting = ;
  } else {
    greeting = ;
  }

  return (
    <div>
      {greeting}
      <p>Welcome to our site.</p>
    </div>
  );
}

8. Conditional Rendering with Else

For more complex conditional rendering, you can use a ternary operator:

function LoadingIndicator({ isLoading }) {
  return (
    <div>
      {isLoading ? (
        <p>Loading...</p>
      ) : (
        <p>Data loaded!</p>
      )}
    </div>
  );
}

Keep in mind that if/else statements and switch statements don‘t work inside JSX because they‘re not expressions (they don‘t resolve to a value). Ternaries and && are the main ways to conditionally render in JSX.

For even more complex conditionals, you can extract the logic into separate functions:

function NotificationBadge({ unreadCount }) {
  return (
    <div>
      {getNotificationText(unreadCount)}
    </div>
  );
}

function getNotificationText(unreadCount) {
  if (unreadCount === 0) {
    return null;
  }

  if (unreadCount < 10) {
    return <span className="badge">{unreadCount}</span>;
  }

  return <span className="badge">9+</span>;
}

9. Passing Data to Child Components

In React, data flows down the component tree via props. To pass data to a child component, you simply add it as an attribute when rendering the child:

function ParentComponent() {
  const data = { message: ‘Hello from parent!‘ };

  return (
    <ChildComponent data={data} />
  );
}

The child component can then access the data via its props:

function ChildComponent({ data }) {
  return (
    <div>
      <p>{data.message}</p>
    </div>
  );
}

It‘s important to remember that props are read-only. A component should never modify its own props directly:

// ❌ Avoid: modifying props
function ChildComponent({ data }) {
  data.message = ‘Modified in child‘;

  return (
    <div>
      <p>{data.message}</p>  
    </div>
  );
}

If a child component needs to modify data, it should be stored in the parent‘s state and passed down as props. The parent can also pass down a callback function to allow the child to indirectly update the parent‘s state:

function ParentComponent() {
  const [message, setMessage] = useState(‘Hello from parent!‘);

  function handleMessageChange(newMessage) {
    setMessage(newMessage);
  }

  return (
    <ChildComponent 
      message={message} 
      onMessageChange={handleMessageChange}
    />
  );
}

function ChildComponent({ message, onMessageChange }) {
  function handleClick() {
    onMessageChange(‘Modified in child‘);
  }

  return (
    <div>
      <p>{message}</p>
      <button onClick={handleClick}>
        Modify Message
      </button>
    </div>
  );
}

This pattern of passing data down and callbacks up is a key concept in React and is necessary for building reusable, composable components.

Bonus Cases

Before we wrap up, let‘s look at a few bonus rendering patterns that are good to have in your toolbox:

  • Fragments: Fragments let you group multiple elements without adding an extra DOM node:

    function MyComponent() {
      return (
        <>
          <ChildA />
          <ChildB />
        </>
      );
    }
  • Shorthand Fragment Syntax: An even terser way to use fragments is with the <></> shorthand syntax:

    function MyComponent() {
      return (
        <>
          <ChildA />
          <ChildB />
        </>  
      );
    }
  • Destructuring Props: If your component receives a lot of props, you can use object destructuring for more readable JSX:

    function UserProfile(props) {
      const { name, age, bio } = props;
    
      return (
        <div>
    
          <p>{age}</p>
          <p>{bio}</p>
        </div>
      );
    }

Conclusion

Mastering these fundamental rendering patterns is crucial for building robust, maintainable React applications. They form the building blocks for more advanced patterns and techniques like higher-order components, render props, and compound components.

As you work on more React projects, you‘ll start to internalize these patterns and reach for them instinctively. However, even experienced developers need a refresher from time to time, which is where a cheatsheet like this comes in handy.

Remember that React‘s component model is designed to be composable and reusable. By keeping your components small, focused, and modular, you‘ll be able to mix and match them like Lego blocks to build complex UIs.

The key to becoming proficient in React is practice. Spend time building small projects and experimenting with different rendering patterns. Don‘t be afraid to make mistakes – that‘s how we learn and grow as developers.

If you want to dive deeper into React rendering, I recommend checking out the official React docs as well as the React Patterns collection.

Happy coding!

Similar Posts