frontend / react / react_fragment.md

React Fragment

3 interview angles 7 min read source

React Fragment

React Fragment is a way to group multiple elements without adding extra DOM nodes, providing a cleaner way to return multiple elements from components.

Table of Contents


What is React Fragment?

React Fragment is a special component that allows you to group multiple elements without creating an additional DOM node.

Key Concepts:

  • No extra DOM node: Groups elements without wrapper div
  • Performance benefit: Reduces DOM complexity
  • Clean JSX: Avoids unnecessary wrapper elements
  • Multiple syntaxes: <> shorthand and <React.Fragment>

Problem Fragment Solves:

// Before Fragment: Extra div wrapper
function App() {
  return (
    <div> {/* Unnecessary wrapper */}
      <h1>Title</h1>
      <p>Paragraph</p>
      <button>Click me</button>
    </div>
  );
}

// With Fragment: No extra wrapper
function App() {
  return (
    <>
      <h1>Title</h1>
      <p>Paragraph</p>
      <button>Click me</button>
    </>
  );
}

Fragment Syntax

1. Shorthand Syntax:

// Short syntax (most common)
function Component() {
  return (
    <>
      <h1>Hello</h1>
      <p>World</p>
    </>
  );
}

// Renders as:
// <h1>Hello</h1>
// <p>World</p>
// (No wrapper element)

2. Full Syntax:

// Full syntax with React.Fragment
import React from 'react';

function Component() {
  return (
    <React.Fragment>
      <h1>Hello</h1>
      <p>World</p>
    </React.Fragment>
  );
}

// Or with destructured import
import React, { Fragment } from 'react';

function Component() {
  return (
    <Fragment>
      <h1>Hello</h1>
      <p>World</p>
    </Fragment>
  );
}

3. Fragment with Keys:

// Fragment with key prop (only available in full syntax)
function List({ items }) {
  return (
    <React.Fragment>
      {items.map(item => (
        <React.Fragment key={item.id}>
          <h3>{item.title}</h3>
          <p>{item.description}</p>
        </React.Fragment>
      ))}
    </React.Fragment>
  );
}

// Usage
const items = [
  { id: 1, title: 'Item 1', description: 'Description 1' },
  { id: 2, title: 'Item 2', description: 'Description 2' }
];

function App() {
  return <List items={items} />;
}

Common Use Cases

1. Returning Multiple Elements:

// Component that needs to return multiple elements
function UserProfile({ user }) {
  return (
    <>
      <h2>{user.name}</h2>
      <p>{user.email}</p>
      <p>{user.role}</p>
      <button>Edit Profile</button>
    </>
  );
}

// Without Fragment, you'd need a wrapper div
function UserProfileWithDiv({ user }) {
  return (
    <div className="user-profile"> {/* Extra wrapper */}
      <h2>{user.name}</h2>
      <p>{user.email}</p>
      <p>{user.role}</p>
      <button>Edit Profile</button>
    </div>
  );
}

2. Conditional Rendering:

// Conditional rendering with Fragment
function ConditionalContent({ showHeader, showFooter, children }) {
  return (
    <>
      {showHeader && <header>Header Content</header>}
      <main>{children}</main>
      {showFooter && <footer>Footer Content</footer>}
    </>
  );
}

// Usage
function App() {
  return (
    <ConditionalContent showHeader={true} showFooter={false}>
      <p>Main content</p>
    </ConditionalContent>
  );
}

3. List Rendering:

// Rendering lists without wrapper
function TodoList({ todos }) {
  return (
    <>
      {todos.map(todo => (
        <div key={todo.id} className="todo-item">
          <span>{todo.text}</span>
          <button>Delete</button>
        </div>
      ))}
    </>
  );
}

// Alternative with Fragment for each item
function TodoListWithFragment({ todos }) {
  return (
    <>
      {todos.map(todo => (
        <React.Fragment key={todo.id}>
          <span>{todo.text}</span>
          <button>Delete</button>
        </React.Fragment>
      ))}
    </>
  );
}

4. Table Structures:

// Table with Fragment (no extra wrapper)
function TableRow({ cells }) {
  return (
    <>
      {cells.map((cell, index) => (
        <td key={index}>{cell}</td>
      ))}
    </>
  );
}

// Usage in table
function DataTable({ data }) {
  return (
    <table>
      <tbody>
        {data.map((row, rowIndex) => (
          <tr key={rowIndex}>
            <TableRow cells={row} />
          </tr>
        ))}
      </tbody>
    </table>
  );
}

5. Form Layouts:

// Form with multiple elements
function FormField({ label, error, children }) {
  return (
    <>
      <label>{label}</label>
      {children}
      {error && <span className="error">{error}</span>}
    </>
  );
}

// Usage
function ContactForm() {
  return (
    <form>
      <FormField label="Name" error="Name is required">
        <input type="text" />
      </FormField>

      <FormField label="Email">
        <input type="email" />
      </FormField>

      <FormField label="Message">
        <textarea />
      </FormField>
    </form>
  );
}

Advanced Fragment Patterns

1. Fragment with Conditional Logic:

// Complex conditional rendering
function ComplexComponent({ user, showDetails, showActions }) {
  return (
    <>
      <h2>{user.name}</h2>

      {showDetails && (
        <>
          <p>Email: {user.email}</p>
          <p>Role: {user.role}</p>
          <p>Department: {user.department}</p>
        </>
      )}

      {showActions && (
        <>
          <button>Edit</button>
          <button>Delete</button>
          <button>Archive</button>
        </>
      )}
    </>
  );
}

2. Fragment with HOCs:

// HOC that returns multiple elements
function withHeaderAndFooter(WrappedComponent) {
  return function EnhancedComponent(props) {
    return (
      <>
        <header>Header from HOC</header>
        <WrappedComponent {...props} />
        <footer>Footer from HOC</footer>
      </>
    );
  };
}

// Usage
const EnhancedComponent = withHeaderAndFooter(MyComponent);

3. Fragment with Context:

// Context provider with Fragment
const ThemeContext = React.createContext('light');

function ThemeProvider({ children, theme }) {
  return (
    <>
      <ThemeContext.Provider value={theme}>
        {children}
      </ThemeContext.Provider>
      <style>{`
        :root {
          --theme: ${theme};
        }
      `}</style>
    </>
  );
}

4. Fragment with Portals:

// Component that renders to multiple places
function ModalWithBackdrop({ children, isOpen }) {
  if (!isOpen) return null;

  return (
    <>
      {ReactDOM.createPortal(
        <div className="backdrop" />,
        document.body
      )}
      {ReactDOM.createPortal(
        <div className="modal">{children}</div>,
        document.body
      )}
    </>
  );
}

5. Fragment with Error Boundaries:

// Error boundary with Fragment
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  render() {
    if (this.state.hasError) {
      return (
        <>
          <h2>Something went wrong</h2>
          <button onClick={() => this.setState({ hasError: false })}>
            Try again
          </button>
        </>
      );
    }

    return this.props.children;
  }
}

Best Practices

1. Use Shorthand When Possible:

// Good: Use shorthand for simple cases
function SimpleComponent() {
  return (
    <>
      <h1>Title</h1>
      <p>Content</p>
    </>
  );
}

// Good: Use full syntax when you need keys
function ListWithKeys({ items }) {
  return (
    <>
      {items.map(item => (
        <React.Fragment key={item.id}>
          <h3>{item.title}</h3>
          <p>{item.description}</p>
        </React.Fragment>
      ))}
    </>
  );
}

2. Don’t Overuse Fragments:

// Good: Use Fragment when you need multiple elements
function GoodComponent() {
  return (
    <>
      <h1>Title</h1>
      <p>Content</p>
    </>
  );
}

// Bad: Don't use Fragment for single element
function BadComponent() {
  return (
    <>
      <h1>Title</h1>
    </>
  );
  // Should just return <h1>Title</h1>
}

3. Consider Semantic HTML:

// Good: Use semantic elements when appropriate
function GoodLayout() {
  return (
    <>
      <header>Header</header>
      <main>Main content</main>
      <footer>Footer</footer>
    </>
  );
}

// Bad: Don't use Fragment when semantic wrapper makes sense
function BadLayout() {
  return (
    <>
      <h1>Header</h1>
      <p>Main content</p>
      <p>Footer</p>
    </>
  );
  // Should use semantic elements or a wrapper
}

4. Handle Keys Properly:

// Good: Use keys with Fragment when needed
function GoodList({ items }) {
  return (
    <>
      {items.map(item => (
        <React.Fragment key={item.id}>
          <h3>{item.title}</h3>
          <p>{item.description}</p>
        </React.Fragment>
      ))}
    </>
  );
}

// Bad: Missing keys can cause issues
function BadList({ items }) {
  return (
    <>
      {items.map(item => (
        <>
          <h3>{item.title}</h3>
          <p>{item.description}</p>
        </>
      ))}
    </>
  );
}

5. Consider Performance:

// Good: Fragment reduces DOM nodes
function EfficientComponent() {
  return (
    <>
      <h1>Title</h1>
      <p>Content</p>
    </>
  );
  // Only 2 DOM nodes: h1 and p
}

// Bad: Wrapper div adds extra DOM node
function InefficientComponent() {
  return (
    <div>
      <h1>Title</h1>
      <p>Content</p>
    </div>
  );
  // 3 DOM nodes: div, h1, and p
}

Common Interview Questions

Q: What is React Fragment?

  • A way to group multiple elements without adding extra DOM nodes.

Q: What are the different ways to write Fragment?

  • Shorthand syntax <> and full syntax <React.Fragment>.

Q: When should you use Fragment?

  • When you need to return multiple elements from a component without a wrapper.

Q: What’s the difference between Fragment and div?

  • Fragment doesn’t create a DOM node, while div creates an extra wrapper element.

Q: Can you use keys with Fragment?

  • Yes, but only with the full <React.Fragment> syntax, not the shorthand <>.

Q: What are the benefits of using Fragment?

  • Cleaner DOM structure, better performance, and more semantic HTML.

Q: When should you use div instead of Fragment?

  • When you need styling, event handling, or refs on the wrapper element.

Q: Can you nest Fragments?

  • Yes, you can nest Fragments, but it’s usually unnecessary.

Q: How does Fragment affect performance?

  • Fragment reduces DOM complexity by eliminating unnecessary wrapper nodes.

Q: What’s the difference between Fragment and array return?

  • Fragment is more readable and doesn’t require keys for static content.

Summary

  • React Fragment allows grouping multiple elements without extra DOM nodes
  • Shorthand syntax <> is preferred for simple cases
  • Full syntax <React.Fragment> is needed when keys are required
  • Common use cases include conditional rendering, lists, and form layouts
  • Performance benefit comes from reducing DOM complexity
  • Best practices include using semantic HTML when appropriate
  • Keys are only available with the full Fragment syntax
  • Understanding Fragment is crucial for writing clean, efficient React components

Interview angle

  • “Why do fragments exist?” - a component must return one node, and a wrapper div breaks layouts that depend on direct parent-child relationships - flex and grid containers, tables, lists. Fragments group without emitting DOM.
  • “When can’t you use the <> shorthand?” - when you need a key, which is the case whenever you map to fragments. Write <React.Fragment key={id}>.
  • “Do fragments cost anything?” - a node in the React tree, nothing in the DOM. Fewer DOM nodes is a real win in large lists and tables.