React(ive) state management

Enter Observables

React's reactivity

Reactivity in real life

Reactivity in modern web

Heinrich Apfelmus

"The essence of a functional reactive programming is to specify the dynamic behavior of the value completely at the time of declaration."

Reactivity refers to how an application automatically updates the UI whenever  application state changes.

Why so Reactive?

Automatic Updates

Improved DX

Enhanced UX

Reduced Code Complexity

03

02

04

01

Coerced v.s. Fine-grained Reactivity

  • Simpler approach
  • Entire UI re-renders whenever the state changes
  • More granular control over UI updates
  • Updates the specific parts of the UI that are affected by the state change

Enter Signals

Nikola Mitrović

Development Lead & Technical Architect

Vega IT

Novi Sad, Serbia

Tech Speaker

State management challenges

Scalability

Predictability

Performance

Maintainability

02

04

Developer Experience

03

01

05

Ratings

  • Excellent 🚀
  • Very good 👍
  • Ok 👌
  • Meh 😒
  • Would not recommend 👎

React

React

Surgical precision 👎

Consistent state 😒

Performance 👎

Easier mental model 😒

Clean dev experience 🚀🚀

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  const incrementCount = () => {
    setCount(count + 1);
  };

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

export default Counter;

SolidJS

SolidJS

Surgical precision 🚀

Consistent state 🚀

Performance 🚀🚀🚀

Easier mental model 🚀🚀

Clean dev experience 👍

import { createSignal, onCleanup } from 'solid-js';

function Counter() {
  const [count, setCount] = createSignal(0);

  const increment = () => setCount(count() + 1);

  // Clean up (e.g., clearing intervals) on component unmount
  onCleanup(() => console.log('Counter component unmounted!'));

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

Enter RxJS

RxJS is a library that enables reactive programming in JavaScript. This means working with data streams and events in a more streamlined and declarative manner.

Observables at the Core

The fundamental building block of RxJS is the Observable. An Observable represents a stream of values (events or data) that can arrive over time.

React-RxJS

React-RxJS

Targeted re-renders 🚀

Consistent state 🚀

Performance 😒

Easier mental model 👍

Clean dev experience 😒

import { bind } from "@react-rxjs/core";
import { createSignal } from "@react-rxjs/utils";
import { shareReplay, takeWhile } from "rxjs/operators";

const [counterChange$, setCounter] = createSignal<number>();
const counterLimit$ = counterChange$.pipe(
    takeWhile((value) => value < 10),
)
const [useCounter] = bind(
  counterChange$.pipe(
    shareReplay(1)
  ),
  0
);

export { useCounter, setCounter };

Entry point to

 

React-RxJS

Recipe request

gRPC streaming

Server URL

RPC method

Request message

Pull v.s. push

React-RxJS docs

"Historically, React uses a pull-based architecture. On the other hand, RxJS uses a push-based approach, where you declaratively define streams and their relationships, and RxJS will propagate every change from one stream to the next one. React-RxJS bridges the gap between these two behaviors."

Enter MobX

Signal-like, targeted re-rendering approach

Minimal boilerplate + Flexibility + DevTools

Simplicity

Performance

MobX

Enter MobX

import { action, makeObservable, observable } from 'mobx';

class AppState {
  constructor() {
    makeObservable(this); // Enable MobX observability
  }

  @observable count = 0; 

  @action increment() {
    this.count++; 
  }
}

export const appState = new AppState();

Surgical precision 🚀

Consistent state 🚀

Performance 👍

Easier mental model 😒

Clean dev experience 🚀

MobX in React 19 (with Compiler)

Some libraries hack up React internals to make signals and fine-grained reactivity work, which often doesn’t work on all platforms and may break if React internals change.

React 19 - Forget Compiler

How much did we move the needle?

Virtual DOM

Zone.js

Dirty Checking

Enter Legend State Observables

Fine-grained reactivity 🔥

No boilerplate 👍

Designed for maximum performance and scalability ⚡️

Super small at 4kb 🐥

Super easy to use 😌

Legend State

Legend State

import { Memo } from "@legendapp/state/react";
import { count$ } from "../state";

const count$ = observable(0);

export const BasicCounter = () => {
  const handleClick = () => count$.set((v) => v + 1);

  return (
    <div>
      <div>
        Legend Count: <Memo>{count$}</Memo>
      </div>
      <button onClick={handleClick}>Add count</button>
    </div>
  );
};

Surgical precision 🚀

Consistent state 🚀

Performance 🚀

Easier mental model 🚀🚀

Clean dev experience 👍

Resources

https://www.builder.io/blog/unified-reactivity-theory

https://www.builder.io/blog/history-of-reactivity

https://www.youtube.com/watch?v=R5AcOtxIdMk

https://www.youtube.com/watch?v=cPVbfiAEbac

https://www.youtube.com/watch?v=l-0fKa0w4ps

https://dev.to/ryansolid/building-a-reactive-library-from-scratch-1i0p

https://legendapp.com/open-source/legend-state/

TanStack Query, Meet RxJS: Building Your Own TanStack Query with Angular & RxJS

Thank you!

n.mitrovic@vegait.rs

You can find me at

Link to the slides

https://github.com/nmitrovic92/reactive-state-managements