Skip to content

Instantly share code, notes, and snippets.

@kennykerr
Created May 29, 2026 12:44
Show Gist options
  • Select an option

  • Save kennykerr/1b52f354496042b138abd835277268dd to your computer and use it in GitHub Desktop.

Select an option

Save kennykerr/1b52f354496042b138abd835277268dd to your computer and use it in GitHub Desktop.

Reactor Framework Comparison

A comparison of four declarative, component-based UI frameworks — the original React (the progenitor) and three reactor-style frameworks sharing the same conceptual lineage: declarative UI with reconciliation.

The goal is not to clone React, but to understand where the state of the art is heading and what ideas can benefit windows-reactor in a Rust/WinUI context.

React windows-reactor Microsoft.UI.Reactor MauiReactor
Repo facebook/react microsoft/windows-rs microsoft/microsoft-ui-reactor adospace/reactorui-maui
Language JavaScript / TypeScript Rust C# C#
UI backend Browser DOM / React Native WinUI 3 (via WinRT/COM) WinUI 3 (direct) .NET MAUI (cross-platform)
Platform Web, iOS, Android, desktop Windows-only Windows-only iOS, Android, Windows, macOS
Status Stable (v19, Dec 2024) Initial (v0.0.0, May 2026) Experimental (April 2026) Stable (NuGet, multi-year)
License MIT MIT / Apache-2.0 MIT MIT

Architecture & Programming Model

Aspect React 19 windows-reactor Microsoft.UI.Reactor MauiReactor
Pattern Functional components with hooks; concurrent rendering Functional MVU with hooks Functional MVU with hooks MVU with class-based state
Component model Functions returning JSX (or class components, legacy) Trait-based (Component<P>) — functions or structs Class-based (Component inherits base) Class-based (Component<TState> or Component<TState, TProps>)
State management useState, useReducer, useContext, useMemo, useCallback, useRef, useEffect, useTransition, useDeferredValue, useOptimistic, useActionState use_state, use_reducer, use_reducer_fn, use_async_state, use_memo, use_ref, use_effect, use_callback, use_context UseState, UseReducer, UseEffect, UseMemo, UseRef, UseObservable, UseCollection SetState(s => ...) mutating a POCO state object; no hooks
Reconciler Fiber-based concurrent reconciler with interruptible rendering, automatic batching, priority lanes Custom keyed-diffing, element pooling, skip-unchanged, render coalescing Virtual element tree, keyed diffing, element pooling, render coalescing, skip-unchanged Visual tree diffing, mounting/unmounting lifecycle
Props Plain JS objects / destructuring Generic P: Clone + PartialEq on component trait Constructor parameters / fluent modifiers [Prop] attribute with source-gen fluent methods, or Props class for navigation
Element tree Virtual DOM (React Elements → Fiber nodes) Enum-based (Element sum type with widget variants) Immutable element descriptions (virtual DOM) VisualNode class hierarchy

DSL & Syntax

React 19 (JavaScript/TypeScript)

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <h1>Count: {count}</h1>
      <div style={{ display: 'flex', gap: 8 }}>
        <button onClick={() => setCount(count - 1)}>-</button>
        <button onClick={() => setCount(count + 1)}>+</button>
      </div>
    </div>
  );
}
  • JSX markup compiled to React.createElement calls
  • Components are plain functions returning JSX
  • Hooks (useState, useEffect, etc.) called at top level
  • Props are destructured JS objects — no special trait or annotation
  • Children via JSX nesting; lists via .map() with key prop
  • React Compiler eliminates manual useMemo/useCallback/React.memo

windows-reactor (Rust)

fn render(&self, _: &(), cx: &mut RenderCx) -> Element {
    let (count, set_count) = cx.use_state(0);
    vstack((
        text_block(format!("Count: {count}")),
        hstack((
            button("-").on_click({
                let s = set_count.clone();
                move || s.call(count - 1)
            }),
            button("+").on_click(move || set_count.call(count + 1)),
        )).spacing(8.0),
    )).into()
}
  • Factory functions: button(label), text_block(text), vstack(children), hstack(children)
  • Fluent modifiers: .margin(...), .background(...), .opacity(...), .with_key(...)
  • Tuple/array-based children: vstack((a, b, c)) or vstack([a, b, c])
  • No macros required; pure Rust expressions

Microsoft.UI.Reactor (C#)

class MyApp : Component {
    public override Element Render() {
        var (count, setCount) = UseState(0);
        return VStack(
            Heading($"Count: {count}"),
            HStack(8,
                Button("-", () => setCount(count - 1)),
                Button("+", () => setCount(count + 1))
            )
        );
    }
}
  • Static factory methods via using static Microsoft.UI.Reactor.Factories
  • Fluent modifier chains (typed)
  • Hooks are methods on the Component base class
  • No XAML, no code-behind, no ViewModels

MauiReactor (C#)

class CounterPageState { public int Counter { get; set; } }

class CounterPage : Component<CounterPageState> {
    public override VisualNode Render()
        => ContentPage("Counter",
            VStack(
                Label($"Counter: {State.Counter}"),
                Button("Click", () => SetState(s => s.Counter++))
            ).Spacing(10).Center()
        );
}
  • Factory methods matching MAUI control names
  • Fluent modifier chains (.Spacing(), .Center(), .FontSize())
  • Class-based state (POCO state class as generic parameter)
  • No hooks — state mutation via SetState lambda
  • Platform extensions: .OnAndroid(...), .OniOS(...), .OnWindows(...)

Feature Matrix

Feature React 19 windows-reactor MS.UI.Reactor MauiReactor
Hooks (useState, etc.) ✅ Full set + new hooks (see below) ✅ Full set ✅ Full set + UseObservable ❌ Class-based state only
React Compiler (auto-memo) ✅ Build-time automatic memoization ❌ (Rust ownership model makes this less needed)
Concurrent rendering ✅ Fiber scheduler, interruptible renders, priority lanes ❌ (single-pass render)
Transitions (useTransition) ✅ Non-blocking state updates with isPending
Deferred values (useDeferredValue) ✅ Show stale UI while fresh content loads
Suspense ✅ Declarative loading states, nested boundaries ❌ (Resource enum with view builder)
Optimistic updates (useOptimistic) ✅ Temporary UI during async Actions
Actions (useActionState) ✅ Async transitions with auto pending/error
Error boundaries ✅ Class-based error boundaries Unknown
Context/providers createContext + useContext + use ✅ (Context<T>, use_context) Likely (React-inspired) ❌ (uses DI instead)
Keyed reconciliation key prop ✅ (via Key property)
Async state ✅ (use hook, Suspense, Actions) ✅ (thread-safe AsyncSetState, use_resource, use_mutation) Unknown Partial (Task-based)
Server Components ✅ (RSC — zero client JS for server-rendered subtrees) N/A (desktop, no server) N/A N/A
Hot reload ✅ (Fast Refresh) ❌ (Rust limitation) ✅ (MetadataUpdateHandler) ✅ (custom hot reload console)
Flex layout (Yoga) ✅ (CSS Flexbox native to web) ✅ (full Yoga port) ❌ (uses MAUI layouts)
Charting ❌ (ecosystem libraries) ✅ (D3 port)
Data grid ❌ (ecosystem libraries) ✅ (DataGrid, PropertyGrid) ❌ (wrap MAUI controls)
Navigation ✅ (React Router, framework routers) ❌ (single-window) ✅ (type-safe routing) ✅ (Shell navigation)
Animations ✅ (CSS transitions, libraries) ✅ (compositor transitions) ✅ (keyframes, connected) ✅ (MAUI animations)
Theming ✅ (Context-based, CSS variables) ✅ (ThemeRef tokens, dark/light) ✅ (ThemeRef, per-control) ✅ (MAUI theming + ThemeKey)
Accessibility ✅ (ARIA attributes, semantic HTML) ✅ (modifiers) ✅ (WCAG 2.1 AA, linting) Partial (MAUI built-in)
Templated/virtual lists ✅ (windowing via react-window/virtuoso) ✅ (list_view, grid_view, recycling) ✅ (ListView, ItemsRepeater) ✅ (CollectionView)
CLI tooling ✅ (create-react-app, Vite, Next.js CLI) ✅ (mur CLI) ✅ (template pack, hot reload CLI)
IDE integration ✅ (VS Code, WebStorm, React DevTools) Standard Rust (rust-analyzer) ✅ (VS Code extension, preview) Standard .NET tooling
Compiler/static analysis ✅ (React Compiler, ESLint plugin) N/A ✅ (Roslyn analyzers)
Localization ❌ (ecosystem: react-intl, i18next) ✅ (ICU, source gen) ❌ (use MAUI localization)
Commanding ✅ (command records, accelerators)
Docking/multi-window ✅ (VS-style docking)
WinForms interop
Shell integration ✅ (taskbar, tray, thumbnails)
DevTools/MCP ✅ (React DevTools, profiler) Diagnostics feature flag ✅ (in-process MCP server)
Cross-platform ✅ (Web; React Native for mobile) ❌ (Windows-only) ❌ (Windows-only) ✅ (iOS, Android, Win, Mac)
AOT support N/A (JIT-compiled JS) Native (Rust) Partial (documented matrix) ✅ (.NET NativeAOT)
Dependency injection ❌ (Context serves this role) Unknown ✅ (via Services property)

Key Differentiators

React 19

  • The original — 10+ years of production use, billions of users, enormous ecosystem
  • React Compiler — build-time automatic memoization eliminates useMemo/useCallback/React.memo boilerplate; Meta saw 31-46% faster PR authoring after removing manual memoization overhead
  • Concurrent rendering — Fiber architecture with interruptible renders, priority lanes, and automatic batching; the UI stays responsive during expensive state transitions
  • Transitions & deferred valuesuseTransition and useDeferredValue let the framework keep the current UI interactive while preparing new state in the background; no jank during filtering, navigation, or data loads
  • Suspense — declarative loading boundaries (<Suspense fallback={...}>) that compose and nest; the framework manages showing/hiding fallbacks automatically
  • Optimistic updatesuseOptimistic gives instant perceived responsiveness during async mutations, with automatic rollback on failure
  • ActionsuseActionState + form actions unify pending state, error handling, and optimistic UI into a single composable pattern
  • use API — read promises and context conditionally in render, enabling patterns that were previously impossible with hooks rules
  • Server Components — zero-JS server-rendered subtrees that reduce bundle size and enable server-side data fetching (web-specific, not directly applicable to desktop)

windows-reactor

  • Rust ownership model — zero-cost abstractions, no GC, no runtime overhead
  • Minimal dependencies — builds on windows-rs ecosystem crates only
  • Backend abstractionBackend trait enables headless testing via RecordingBackend
  • Extremely lean — ~105K lines total (incl. generated bindings); no CLI, no hot reload, no IDE plugin
  • Build-time code generationbuild.rs generates WinUI bindings at compile time
  • Designed for embedding — can integrate into existing windows-rs applications

Microsoft.UI.Reactor

  • Most feature-complete — charting, data grids, docking, shell integration, commanding, localization, flex layout
  • AI-first development — ships agent plugins, MCP server, SKILL.md for AI assistants
  • Full toolchainmur CLI, VS Code extension, Roslyn analyzers, project templates
  • Directly backed by the WinUI team — features designed to flow back into WinUI itself
  • Hot reload + live preview — iterate without restarting
  • Extensive testing — 2,200+ unit tests, Appium e2e, stress/perf benchmarks

MauiReactor

  • Cross-platform — single codebase for iOS, Android, Windows, macOS
  • Production-ready — stable NuGet, years of community usage, documentation, videos
  • Familiar to .NET developers — standard POCO state, no hooks to learn
  • Source generators[Scaffold] auto-generates wrapper classes for native MAUI controls
  • Hot reload — works across all platforms including mobile emulators
  • Community ecosystem — sample apps, third-party controls, active GitHub community

Lessons from React 19 for windows-reactor

React is the progenitor of the component/hooks model that windows-reactor adopts. Rather than cloning React features verbatim, the following analyzes which React 19 advances have analogues or inspiration value for a Rust/WinUI desktop framework.

1. Automatic Memoization (React Compiler)

What React does: The React Compiler is a build-time Babel plugin that automatically inserts useMemo, useCallback, and React.memo calls. At Meta, only ~8% of PRs used manual memoization, and those PRs took 31-46% longer to author. The compiler eliminates this cognitive overhead entirely.

Relevance to windows-reactor: Rust's ownership model already provides some of this benefit — Clone + PartialEq props naturally enable skip-unchanged diffing, and there is no equivalent of JavaScript's referential-identity footgun where {} !== {}. However, windows-reactor could benefit from:

  • Compile-time diffing hints — a proc-macro or build.rs pass that analyzes component render functions and auto-derives smarter diffing (e.g., field-level partial comparison rather than full PartialEq)
  • Memoization of expensive element subtreesuse_memo exists but could be more ergonomic; consider whether the reconciler itself can detect stable subtrees without explicit memoization
  • Lint/clippy rules enforcing "rules of hooks" at compile time, analogous to React Compiler's ESLint plugin

2. Concurrent Rendering & Transitions

What React does: React's Fiber architecture enables interruptible rendering — a large re-render can be paused mid-tree to handle a higher-priority update (e.g., user typing), then resumed. useTransition marks state updates as non-urgent, keeping the current UI interactive while React prepares the new state in the background. useDeferredValue lets a value "lag behind" so that expensive subtrees render with stale data while urgent updates (like input) remain responsive.

Relevance to windows-reactor: This is one of React's most architecturally significant advances. The current reconciler does a single-pass synchronous diff+patch. For most desktop UIs this is fine, but for complex scenarios (large lists, real-time data, multi-pane layouts) it could cause frame drops. Potential approaches:

  • use_transition hook — mark expensive state updates as "low priority," allowing the framework to keep the UI responsive (show is_pending flag) while computing the new tree. The reconciler would need to support yielding mid-diff or splitting work across frames.
  • use_deferred_value hook — return the previous value during expensive re-renders. Simpler to implement than full concurrent rendering — doesn't require an interruptible reconciler, just a "double-buffer" of state with intelligent scheduling.
  • Render coalescing already exists; the next step would be render prioritization — urgent updates (input, scrolling) preempt batch updates (data loads, tab switches).

3. Suspense Boundaries

What React does: <Suspense fallback={<Loading />}> wraps any subtree that may need to load data or code. When a child suspends (throws a Promise), React shows the fallback automatically. Suspense boundaries compose and nest — each boundary controls its own loading state independently. Combined with transitions, Suspense avoids jarring "flash to spinner" by keeping stale content visible during navigation.

Relevance to windows-reactor: The Resource<T> enum with view() builder pattern already fills part of this role — it provides Loading, Ready, Reloading, and Error states. However, it is per-resource, not per-subtree. A Suspense-like boundary would enable:

  • Coordinated loading — wrap multiple use_resource calls in a single boundary so they all appear together (React's "reveal content together" pattern)
  • Nested loading sequences — outer skeleton → inner content, without manually threading loading state through every component
  • Cleaner component APIs — components wouldn't need to return ResourceView; they could simply call cx.use_resource(...) and let a parent Suspense boundary handle the loading UI
  • Implementation: a suspense(fallback, children) element where child components can "suspend" by returning a sentinel, causing the reconciler to render the fallback subtree until all children are ready

4. Optimistic Updates

What React does: useOptimistic shows a temporary state during an async Action. If the Action succeeds, the real state replaces the optimistic value seamlessly. If it fails, React automatically reverts to the pre-optimistic state. This makes mutation-heavy UIs (like/unlike, add to cart, inline editing) feel instant.

Relevance to windows-reactor: use_async_state and use_mutation provide the async write path, but the developer must manually manage the "show optimistic value, then replace with real value, then handle rollback" pattern. A dedicated use_optimistic hook would:

let (optimistic_name, set_optimistic) = cx.use_optimistic(current_name);
// Inside an async action:
set_optimistic("New Name".to_string());
let result = save_name("New Name").await;
// On success: real state updates, optimistic value converges
// On failure: automatic rollback to current_name

This composes naturally with use_async_state and could be built as a higher-level hook on top of existing primitives.

5. Actions & Form State

What React does: React 19's useActionState unifies three concerns that previously required manual wiring:

  1. Pending stateisPending is true while the action runs
  2. Error state — the action returns error data that the component renders
  3. Sequential ordering — later actions supersede earlier ones automatically

Combined with <form action={fn}>, this creates a declarative mutation model where the framework handles the entire submit → pending → success/error lifecycle.

Relevance to windows-reactor: Desktop forms (settings pages, data entry, dialogs) have the same pending/error/success lifecycle. A use_action hook could combine use_async_state + use_reducer into a single pattern:

let (error, submit, is_pending) = cx.use_action(|_prev, form_data: FormData| async move {
    match save_settings(form_data).await {
        Ok(_) => None, // no error
        Err(e) => Some(e.to_string()),
    }
});

This is less urgent than transitions or Suspense, but would reduce boilerplate for form-heavy apps.

6. The use API (Conditional Resource Reading)

What React does: The use API lets you read a Promise or Context conditionally in render — after early returns, inside loops, or in branches. Unlike hooks (which must be called unconditionally at the top level), use can be called anywhere. This unlocks patterns like "if no children, return null; otherwise read theme context."

Relevance to windows-reactor: Rust's hooks must currently be called unconditionally and in consistent order (same as React's traditional hooks rules). A use-like API is harder in Rust because there's no equivalent of throwing a Promise. However:

  • For context, cx.use_context(ctx) could be made safe to call conditionally if context reads are implemented as lookups rather than positional hooks
  • For resources, a cx.use(future) that integrates with a Suspense-like boundary could replace the current use_resource when the component wants to "just get the data or suspend trying"
  • This is a stretch goal — the current hooks model works well, and conditional hooks are a convenience, not a necessity

7. Compiler & Static Analysis

What React does: Beyond automatic memoization, the React Compiler includes an ESLint plugin that statically identifies "Rules of React" violations — stale closures, hook ordering bugs, mutation of props during render. Meta plans to eventually require the compiler for new React features.

Relevance to windows-reactor: Rust's type system already prevents many classes of bugs that the React Compiler catches (use-after-move, data races, mutation of borrowed data). However, a #[clippy::reactor] lint group could catch reactor-specific issues:

  • Hooks called conditionally or inside loops
  • SetState captured but never called (likely dead code)
  • use_effect with empty deps that references changing state (stale closure equivalent in Rust closures)
  • Components that clone large props unnecessarily

What to Deprioritize

Some React 19 features are not relevant to windows-reactor:

  • Server Components / Server Actions — web-specific; desktop apps don't have a server/client split
  • <form> Actions with automatic reset — HTML-form-specific; WinUI has different form controls
  • Streaming SSR / Selective Hydration — server rendering concepts
  • React Native bridge — mobile cross-platform, not applicable to WinUI-only

Gaps in windows-reactor (relative to all four)

Gap Impact Notes
No concurrent/interruptible rendering Frame drops possible with complex UIs React's Fiber scheduler is the gold standard; could start with use_transition
No Suspense boundaries Per-resource loading only, not per-subtree Resource<T>.view() exists; Suspense would compose loading across components
No transitions/deferred values All state updates are equally urgent use_transition + use_deferred_value would improve perceived responsiveness
No optimistic updates Manual rollback logic for async mutations use_optimistic could be a thin layer over use_async_state
No hot reload Slower iteration cycle Inherent Rust limitation; mitigated by fast compile times and headless tests
No navigation/routing Single-window only Could be added; the Window abstraction exists
No CLI/templates Manual project setup Could ship a cargo-generate template
No flex layout Limited layout options Has StackPanel, Grid, Canvas, RelativePanel — covers most cases
No charting/data grid Enterprise gap Focused on core framework first
No commanding Manual accelerator wiring Keyboard accelerators exist but not unified command model
No localization framework Manual i18n Standard Rust i18n crates can fill this
No cross-platform Windows-only By design — uses WinUI directly for maximum fidelity
No AI/agent integration No MCP/plugin story Diagnostic hooks exist; could be extended
No static analysis / lint rules Reactor-specific bugs not caught at compile time Rust's type system covers most, but hooks-order lints would help

Overlap / Shared DNA

All four frameworks share:

  1. Virtual element trees diffed against previous renders to minimize UI mutations
  2. Factory-function DSL replacing markup (XAML/XML/HTML) with typed code (React uses JSX which compiles to function calls)
  3. Fluent modifier chains for styling and layout (React uses props/style objects instead of method chains, but the concept is the same)
  4. Keyed reconciliation for efficient list updates
  5. Component composition as the primary abstraction
  6. Unidirectional data flow — state flows down, events flow up (React: "lifting state up"; reactor: props + callbacks)
  7. Hooks as the primary state/effect mechanism (React, windows-reactor, MS.UI.Reactor; MauiReactor diverges with class-based state)

The programming model is closest between windows-reactor and React — both use functional components with hooks (use_state/useState, use_effect/useEffect, etc.). Microsoft.UI.Reactor is the C# equivalent. MauiReactor diverges most with class-based state and cross-platform targeting.

React 19's newest innovations — concurrent rendering, transitions, Suspense, optimistic updates, and the compiler — represent the frontier. These ideas are proven at Meta's scale (Facebook, Instagram, Threads) and are the direction the ecosystem is moving. windows-reactor should selectively adopt the patterns that make sense for desktop Rust, particularly transitions, Suspense boundaries, and optimistic updates.


Summary

If you want… Use…
Web/mobile, massive ecosystem, cutting-edge concurrent rendering React
Maximum performance, Rust, minimal footprint, Windows-only windows-reactor
Full-featured declarative WinUI with C#, AI-assisted dev, enterprise features Microsoft.UI.Reactor
Cross-platform mobile+desktop with declarative C# MauiReactor

windows-reactor occupies a unique niche: it brings the React/hooks programming model to Rust developers targeting Windows, with the safety and performance characteristics of Rust. It is the leanest of the four and the most suitable for embedding into existing Rust/Windows applications or system-level tools that need a UI layer without a managed runtime.

Prioritized React-Inspired Roadmap Items

Based on the analysis above, these are the highest-value React 19 features to adapt for windows-reactor, in rough priority order:

  1. use_transition + use_deferred_value — relatively low implementation cost, high UX impact for responsive UIs during expensive state changes
  2. Suspense boundaries — composable loading states across component trees, building on the existing Resource<T> primitives
  3. use_optimistic — thin convenience hook over existing async state for instant perceived responsiveness
  4. use_action (action state) — unified pending/error/success pattern for form-like workflows
  5. Hooks-order linting — clippy lint or proc-macro to catch common reactor-specific mistakes
  6. Interruptible reconciler — the most ambitious item; would require fundamental changes to the render pipeline, but would enable true concurrent rendering
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment