single-spa-react

6.0.2 · active · verified Sun Apr 19

single-spa-react is a utility library designed to simplify the integration of React applications and components into a single-spa microfrontend architecture. It provides helper functions that adapt React's rendering and lifecycle methods (bootstrap, mount, unmount) to single-spa's expectations. The current stable version is 6.0.2, with ongoing active development including patch releases and a v7.0.0-beta.0 in progress. Key differentiators include robust support for React 18's `createRoot` API, explicit compatibility options for older React versions, built-in error boundary mechanisms, and a dedicated `<Parcel>` component for managing framework-agnostic micro-frontends within a React application. It focuses on ensuring React applications adhere to single-spa's lifecycle contracts and work seamlessly within a polyglot microfrontend environment.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to wrap a React application for single-spa using `single-spa-react`. It showcases React 18's `ReactDOMClient`, integrates an error boundary, and defines the `domElementGetter` for mounting.

import React from 'react';
import ReactDOMClient from 'react-dom/client'; // For React 18+
import singleSpaReact from 'single-spa-react';

// A simple React component for the microfrontend
const MyReactApp = ({ name, mountParcel }) => {
  const [count, setCount] = React.useState(0);

  React.useEffect(() => {
    console.log(`${name} mounted!`);
    return () => console.log(`${name} unmounted!`);
  }, [name]);

  return (
    <div style={{
      padding: '20px',
      border: '1px solid #61dafb',
      borderRadius: '8px',
      margin: '10px',
      backgroundColor: '#282c34',
      color: 'white'
    }}>
      <h2>Hello from {name}!</h2>
      <p>Count: {count}</p>
      <button onClick={() => setCount(c => c + 1)} style={{ padding: '8px 16px', borderRadius: '4px', cursor: 'pointer' }}>Increment</button>
      <p>This is a single-spa React application.</p>
      {/* Optionally mount a parcel here */}
      {/* <Parcel config={mountParcel} wrapWith='div' /> */}
    </div>
  );
};

// A basic error boundary component is highly recommended for robustness.
class ErrorBoundary extends React.Component {
  state = { hasError: false };
  static getDerivedStateFromError(error) { return { hasError: true }; }
  componentDidCatch(error, errorInfo) {
    console.error("React component error:", error, errorInfo);
  }
  render() {
    if (this.state.hasError) {
      return <h1 style={{ color: 'red' }}>Something went wrong in {this.props.name}.</h1>;
    }
    return this.props.children;
  }
}

// Configure single-spa-react with your React application.
const lifecycles = singleSpaReact({
  React, // Pass the React library
  ReactDOMClient, // Use ReactDOMClient for React 18+ for createRoot. For React 17-, use ReactDOM and specify renderType: 'render'.
  rootComponent: MyReactApp, // Your top-level React component
  // A function that returns the DOM element where the React app will be mounted.
  domElementGetter: () => {
    let el = document.getElementById('react-app-container');
    if (!el) {
      el = document.createElement('div');
      el.id = 'react-app-container';
      document.body.appendChild(el); // Append to body or a specific parent defined in your root config
    }
    return el;
  },
  // Recommended: Provide an error boundary for better fault tolerance.
  errorBoundary: ErrorBoundary,
  // Optional: Pass custom props to your root component.
  getAppProps: ({ name, ...props }) => ({ name: name || 'Default React App', ...props }),
  // Suppress warning if using an errorBoundary function/class
  suppressComponentDidCatchWarning: true
});

// Export single-spa lifecycles for your microfrontend.
export const { bootstrap, mount, unmount } = lifecycles;

view raw JSON →