---
title: "RxJS for React: Unlocking Reactive States"
published_at: "2024-12-17T10:06:35+00:00"
modified_at: "2026-02-10T13:12:46+00:00"
url: "https://www.syncfusion.com/blogs/post/react-rxjs-reactive-programming"
excerpt: "Unlock the potential of React-RxJS for reactive state management, seamless asynchronous operations, and more in your React projects."
taxonomy_category:
  - "Development"
  - "React"
  - "Web"
taxonomy_post_tag:
  - "development"
  - "productivity"
  - "React"
  - "ReactJS"
  - "Web"
---

# RxJS for React: Unlocking Reactive States

[Vinoth Kumar Sundara Moorthy](https://www.syncfusion.com/blogs/author/vinoth-kumar-sundara-moorthy)

![RxJS for React: Unlocking Reactive States](https://www.syncfusion.com/blogs/wp-content/uploads/2024/12/RxJS-for-React-Unlocking-Reactive-States.jpg)


**TL;DR:** React-RxJS combines the declarative power of React with the reactive programming capabilities of RxJS, making it ideal for handling complex state updates, asynchronous tasks, and real-time events in your apps.

As we know, [React](https://react.dev/)
 is one of the most popular JavaScript libraries for building user interfaces. Developers use its declarative approach to describe how a UI should look according to the application’s current state, and React efficiently updates the UI whenever the state changes.

The [RxJS](https://rxjs.dev/)
 (reactive extensions for JavaScript) library lets developers work with asynchronous data streams and events in a declarative and composable way. It uses observables, which are sequences of values that unfold over time, to represent various data sources like user clicks and API requests.

The combination of React’s declarative UI approach and RxJS’s reactive programming capabilities creates a powerful synergy for building modern web apps. [React-RxJS](https://react-rxjs.org/)
 becomes particularly valuable when handling complex state management, asynchronous data streams, and real-time events.


## Understanding React-RxJS

[React-RxJS](https://react-rxjs.org/)
 is a library that seamlessly integrates the power of RxJS into React apps. It provides a set of tools and utilities that allow developers to manage state and side effects reactively. At the heart of React-RxJS is the concept of using streams as state. RxJS streams, with their declarative nature, are used to represent and manage the state of a React app. They only execute effects when subscribed to, meaning state changes are handled efficiently.

Let’s explore the advantages of using React-RxJS:

- **Improved scalability for complex states:** React-RxJS excels in managing complex state scenarios. By leveraging RxJS operators, developers can handle intricate state transformations and updates efficiently, ensuring the app remains scalable as complexity grows.
- **Better handling of async data streams**: React-RxJS simplifies the handling of asynchronous data streams, a common requirement in modern apps. With RxJS, developers can manage API requests, user interactions, and other async events in a streamlined and declarative way, improving code readability and maintainability.
- **Reducing prop drilling and improving component isolation:** React-RxJS can help minimize prop drilling, a common issue in React apps where data is passed down through multiple layers of components. By using observables to manage state, components can directly subscribe to the data they need, reducing unnecessary props and improving component isolation.

## Setting up React-RxJS

To use React-RxJS effectively, a basic understanding of both React and RxJS is essential. Familiarity with React concepts like components, state, and hooks is important, along with a grasp of RxJS fundamentals such as observables, observers, and operators.

To install React-RxJS in your React project, use the following npm command.

```
npm install @react-rxjs/core rxjs
```

This command installs the core React-RxJS library, providing the essential tools for integration, and RxJS, the reactive programming library itself.


## Core concepts in React-RxJS

### Bind and create signals

React-RxJS utilizes the [bind()](https://react-rxjs.org/docs/api/core/bind#:~:text=Binds%20an%20Observable%20to%20React,stream%20representing%20the%20source%20Observable.)
 function and [createSignal()](https://react-rxjs.org/docs/api/utils/createSignal#:~:text=createSignal()-,createSignal(),consumer%20and%20the%20producer%20split.)
 function for reactive state management. The **createSignal()** function from **@react-rxjs/utils** is comparable to using a subject and acts as an entry point for React-RxJS. It separates the producer and consumer of a subject, enabling the creation of an entry point for your streams.

```
import { createSignal } from '@react-rxjs/utils';

// Create a signal for new to-dos.
const [newTodo$, postNewTodo] = createSignal<string>();

// Example usage in a component.
const TodoForm = () => {
  const [todo, setTodo] = useState('');

// Example usage in a component.
const TodoForm = () => {
  const [todo, setTodo] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    postNewTodo(todo);
    setTodo('');
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={todo}
        onChange={(e) => setTodo(e.target.value)}
        placeholder="Add a new to-do"
      />
      <button type="submit">Add To-Do</button>
    </form>
  );
};
```

For example, in a local to-dos app, you can define your state using **createSignal()** to handle new to-dos. In this case, the ** TodoForm** component can directly call ** postNewTodo()**whenever the user adds a to-do, and the change will be updated in the to-do list.

The **bind()** function connects a stream to a hook, and it returns a tuple that contains the hook and the underlying shared observable. This underlying observable can then be used by other streams. Following is an example of using ** bind()**and ** createSignal()**to manage a counter.

```
import { bind } from '@react-rxjs/core';
import { createSignal } from '@react-rxjs/utils';
import { map, scan } from 'rxjs/operators';

// Create a signal for incrementing the counter.
const [increment$, increment] = createSignal<void>();

// Create a stream that calculates the counter value.
const counter$ = increment$.pipe(
  scan((count) => count + 1, 0)
);

// Bind the stream to a hook.
const [useCounter, counterObservable] = bind(counter$, 0);

// Example usage in a component.
const Counter = () => {
  const count = useCounter();

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
};
```

### Connect observables to components

To subscribe to RxJS streams within your React components, you can use React-RxJS utilities.

First, let’s set up a simple counter observable and bind it to a hook.

```
import { bind, Subscribe } from '@react-rxjs/core';
import { interval } from 'rxjs';
import { map } from 'rxjs/operators';

// Create a stream that emits a value every second.
const counter$ = interval(1000).pipe(
  map((value) => value + 1)
);

// Bind the stream to a hook.
const [useCounter, counterObservable] = bind(counter$, 0);
```

Now, let’s use the [<Subscribe>](https://react-rxjs.org/docs/api/core/subscribe)
 component to connect the observable to our React component.

```
import React from 'react';

const Counter = () => {
  const count = useCounter();

  return (
    <div>
      <p>Count: {count}</p>
    </div>
  );
};

const App = () => (
  <Subscribe source$={counterObservable}>
    <Counter />
  </Subscribe>
);

export default App;
```

The primary utility is the **<Subscribe>** component. The **<Subscribe>** component renders its children after subscribing to the ** source$** observable. Initially, it renders ** null**, and then it will render the children once it has subscribed to the stream. It also subscribes to all observables utilized by its children, as if it were a React context. In cases where the default value is provided to the ** bind()**function and no subscribers are present, the component will return the default value on the first render and subscribe to the source after mounting. If there is an active subscription before mounting, the component will retrieve the current value directly.

For components that don’t have a default value, ensure an active subscription to the observable before the component using the hook is invoked. The **<Subscribe>** component is a helpful tool for managing this.

### Shared state across components

React-RxJS enables the sharing of the reactive state among multiple components. This is made possible because **bind()** uses the **shareLatest** operator. The ** shareLatest** operator multicasts the stream, resulting in a single subscription to the source. Consequently, any changes are propagated to all subscriptions associated with the shared stream.

Building on the previous example, multiple components can utilize **useFirst5SpacedNumbers** to access and display the shared counter state.

```
const NumberDisplay1 = () => {
  const count = useCounter();
  return (
    <div>
      <p>Number Display 1: {count}</p>
    </div>
  );
};

const NumberDisplay2 = () => {
  const count = useCounter();
  return (
    <div>
      <p>Number Display 2: {count}</p>
    </div>
  );
};

const App = () => (
  <Subscribe source$={counterObservable}>
    <NumberDisplay1 />
    <NumberDisplay2 />
  </Subscribe>
);
```

In this scenario, both the **NumberDisplay1** and ** NumberDisplay2** components will display the same counter value, reflecting the shared state facilitated by React-RxJS.

### Error handling

Error handling is addressed in React-RxJS by leveraging React’s error boundaries. If an error occurs in a stream, the error will be propagated to the nearest error boundary defined for the component that uses the stream, enabling graceful error recovery. When a stream encounters an error, it is immediately closed. Then, if the recovery strategy involves retrying, the **&<Subscribe>** boundary will resubscribe to the stream, effectively starting a new subscription from the beginning.

React-RxJS offers a comprehensive approach to reactive state management, encompassing error handling, shared state management, and connecting observables to components.


## Real-world use cases

### Asynchronous data fetching

React-RxJS is effective for fetching data from APIs and displaying it in React components. Consider an example of fetching a list of to-dos from a JSONPlaceholder API.

```
import { bind, Subscribe } from '@react-rxjs/core';
import { fromFetch } from 'rxjs/fetch';
import { switchMap } from 'rxjs/operators';

const [useTodos, todos$] = bind(
  fromFetch('https://jsonplaceholder.typicode.com/todos').pipe(
    switchMap((response) => response.ok ? response.json() : throw new Error('Failed to fetch todos'))
  ), 
  [] 
);

const Todos = () => {
  const todos = useTodos();
  return (<ul>{todos.map((todo) => (<li key={todo.id}>{todo.title}</li>))}</ul>); 
};

const App = () => (<Subscribe source$={todos$}><Todos /></Subscribe>);
```

The **fromFetch** function initiates the API request. ** switchMap** handles the response, parsing it as JSON if successful or throwing an error if it fails. ** bind** connects the observable to the custom hook ** useTodos**, providing an initial empty array while fetching data. The ** Todos** component utilizes ** useTodos** to display the fetched data. The ** App** component uses the **<Subscribe>** component to subscribe to ** todos$** and update the ** Todos** component with the fetched data.

### Event streams

React-RxJS simplifies the handling of user interaction streams, such as button clicks and search input changes. Following is how to create a search autocomplete that captures user input using **fromEvent** and ** bind**.

```
import { bind, Subscribe } from '@react-rxjs/core';
import { fromEvent } from 'rxjs';

const [useSearchTerm, searchTerm$] = bind(fromEvent(searchInput, 'input'), '');

const App = () => (
  <input type="text" onChange={(e) => useSearchTerm(e.target.value)} />
);
```

In the previous code example, **fromEvent** creates an observable, ** searchTerm$**, that emits the search input’s value on user input. ** bind** connects ** searchTerm$** to the ** useSearchTerm** hook. The ** App** component renders an input field. Use ** useSearchTerm** to update the search term when the input changes.

### Global state management

While not a direct replacement for dedicated state management libraries like Redux, React-RxJS can handle global state management in some cases.

Let’s imagine you want to manage a dark theme preference globally in your app. The following code example illustrates a simplified implementation.

```
import { bind, createSignal, Subscribe } from '@react-rxjs/core';

// Create a signal for managing the dark mode state.
const [useDarkMode, darkMode$] = bind(createSignal(false), false);

// Component to toggle dark mode.
const DarkModeToggle = () => {
  const darkMode = useDarkMode(); 
  const toggleDarkMode = () => useDarkMode(!darkMode);

  return <button onClick={toggleDarkMode}>Toggle Dark Mode</button>;
};

// A component that reacts to dark mode changes.
const MyComponent = () => {
  const darkMode = useDarkMode();
  return <div className={darkMode ? 'dark-mode' : 'light-mode'}>My Component</div>;
};

// Main application component.
const App = () => (
  <Subscribe source$={darkMode$}>
    <DarkModeToggle />
    <MyComponent />
  </Subscribe>
);
```

In the previous example, **createSignal** is used to create a signal that manages the ** darkMode** state. ** bind** connects this signal to the ** useDarkMode** hook, which components can use to access and update the state. The **<Subscribe>** component in the ** App** component ensures that both the ** DarkModeToggle** and ** MyComponent** will react to changes in the ** darkMode** state.

## Comparing React-RxJS with other solutions

### React’s built-in state management

React’s built-in hooks, like **useState** and ** useReducer,** are suitable for managing simple states within components. However, as state complexity grows and asynchronous operations become involved, React-RxJS offers a more declarative and manageable approach.

### Other state management tools (Redux, MobX, Zustand)

Redux offers a robust and widely used solution for global state management, but it can introduce boilerplate code. **MobX** provides a reactive approach but relies on object-oriented programming. ** Zustand** is a lightweight state management library that emphasizes simplicity. React-RxJS shines when:

- You need to manage complex, asynchronous data streams.
- You prefer a declarative and composable approach to state management.
- You want to reduce prop drilling and improve component isolation.

In situations where state management requirements involve intricate asynchronous data flows, React-RxJS can be a strong choice over alternatives.

## Best practices for using React-RxJS

### Organize code for scalability

To enhance code scalability, it’s advisable to separate observables and signals from your React components. This separation promotes better organization and maintainability. A suggested approach is to create dedicated files or modules to house your observables and signals. For instance, you could have a **services** directory where you define and export your RxJS streams. By centralizing this logic, you improve code reusability and reduce potential conflicts.

### Minimize subscriptions in components

To prevent memory leaks in your React app, it’s essential to minimize subscriptions within components. When a component subscribes to an observable, it establishes a connection that needs to be terminated when the component unmounts. If this connection is not properly closed, it can lead to memory leaks.

Utilize the **<Subscribe>** component from React-RxJS to manage subscriptions effectively. The **<Subscribe>** component handles the subscription to the observables and automatically unsubscribes when the component unmounts, ensuring proper cleanup.

### Use RxJS operators wisely

RxJS operators provide powerful tools for manipulating and transforming data streams. However, it’s important to use operators to maintain stream clarity and performance. Employ operators that align with your specific use case. For example, if you need to limit the rate of emissions from an observable, consider using **debounceTime** or ** throttleTime**.

Thorough testing of your RxJS logic is recommended to ensure streams behave as expected and that performance is not negatively impacted.

### Benefits of React-RxJS

- **Efficient asynchronous operations**: React-RxJS provides a structured way to handle asynchronous operations, simplifying the management of complex async flows and avoiding callback hell and deeply nested promises.
- **Reactive state management**: RxJS observables empower developers to manage and react to changes in app state in a declarative and responsive way.
- **Declarative event handling**: Observables allow you to declare how your components should respond to user interactions and events, resulting in more maintainable and understandable code.
- **Streamlined data flow**: RxJS enables the orchestration of data flow among different parts of your app, simplifying data synchronization. React-RxJS is particularly well-suited for apps with complex data streams and asynchronous workflows. Whether you’re dealing with real-time updates, user interactions, or API calls, React-RxJS can simplify your state management and event-handling logic.


## Conclusion

React-RxJS bridges the gap between React’s pull-based architecture and RxJS’s push-based approach, facilitating the creation of scalable and reactive React apps. By combining these two technologies, developers can manage state in a declarative and efficient manner, reducing the complexity often associated with asynchronous operations and event handling.

## Related Blogs



[Introducing the New React Smart TextArea Component](https://www.syncfusion.com/blogs/post/new-react-smart-textarea-component)



[Introducing New AI-Powered Smart React Components and Features](https://www.syncfusion.com/blogs/post/new-ai-powered-smart-react-components)



[Svelte vs React: Which Framework to Choose?](https://www.syncfusion.com/blogs/post/svelte-vs-react-choose-the-right-one)



[React vs. Next.js: Choosing the Right Framework](https://www.syncfusion.com/blogs/post/react-vs-nextjs)
