DEV Community

nihil-pro
nihil-pro

Posted on

Observable – Just Pure, Predictable Reactivity

Tired of boilerplate-heavy state management? Observable is a lightweight, intuitive library that brings seamless reactivity to JavaScript with minimal effort.

Why Observable?

Observable is inspired by MobX but designed to be even simpler. It gives you complete freedom to update state anywhere — even inside effects or reaction callbacks. No special wrappers, annotations, or strict rules are needed. Just modify your data naturally, and Observable automatically tracks changes and updates exactly what needs to change.

  • Simple: Write plain JavaScript — no complex APIs;
  • Reactive: Automatically syncs state and UI;
  • Tiny: 3KB gzipped, zero dependencies;
  • Async-friendly: Handle asynchronous operations without extra syntax.

Example: Dynamic Post Viewer

Let’s build a post viewer that:

  • Fetches posts on demand
  • Handles loading/error states
  • Updates the UI automatically

Define State (Plain JS Class):

const API = 'https://jsonplaceholder.typicode.com/posts'

class State {
  loading = true;
  postId = 1;
  post = null;
  error = null;

  async getPost() {
    try {
      this.loading = true;
      const response = await fetch(`${API}/${this.postId}`);
      this.post = await response.json();
      this.error = null;
    } catch (error) {
      this.post = null;
      this.error = error.message;
    } finally {
      this.loading = false;
    }
  }
}
const state = new State();
Enter fullscreen mode Exit fullscreen mode

Create React Component:

function Posts() {
  return (
    <div>
      {state.loading ? "Loading..." : null}
      {state.post ? (
        <h2>{state.post.title}</h2>
      ) : (
        <p>Error: {state.error || "No post found."}</p>
      )}
      <button onClick={() => state.postId--}>Prev</button>
      <button onClick={() => state.postId++}>Next</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Add Reactivity (3 Lines!):

import { Observable, autorun } from "kr-observable";
import { observer } from "kr-observable/react";

// 1. Implement reactive state by extending Observable
class State extends Observable { /* ... */ }

// 2. Convert Posts to observable component
export const ObservedPosts = observer(Posts);

// 3. Auto-fetch posts when postId changes
autorun(state.getPost);
Enter fullscreen mode Exit fullscreen mode

That’s it! Now:

  • Clicking Prev/Next auto-fetches new posts;
  • Loading and error states update instantly;
  • No manual subscriptions.

Try it on stackblitz.com

Final code
import { Observable, autorun } from 'kr-observable'
import { observer } from 'kr-observable/react'

class State extends Observable {    
  loading = true;    
  postId = 1;    
  post = null;  
  error = null;  

  async getPost() {    
    try {    
      this.loading = true;    
      const response = await fetch(`/posts/${this.postId}`);  
      this.post = await response.json();  
      this.error = null;  
    } catch (error) {  
      this.post = null;  
      this.error = error.message;  
    } finally {  
      this.loading = false;  
    }  
  }  

  prev() {
    this.postId -= 1;
  }

  next() {
    this.postId += 1;
  }
}  

const state = new State();

const dispose = autorun(state.getPost);

function Posts() {
  return (
    <div>
      <div>Loading: {String(state.loading)}</div>

        {state.post ? (
          <h2>{state.post.title}</h2>
        ) : (
          <p>Error: {state.error || "No post found."}</p>
        )}

        <div>
          <button onClick={state.prev}>
            Prev
          </button>
          <button onClick={state.next}>
            Next
          </button>
        </div>
     </div>
  );
}

export const ObservedPosts = observer(Posts)
Enter fullscreen mode Exit fullscreen mode

What else?

Observable can do much more. It includes built-in adapters for React, Preact and Vue. Uses 38% less memory than Redux in benchmarks, and is really friendly.

Learn More

Discussion

  • MobX users: How does this compare to your experience?
  • What’s missing? What would make Observable better for your projects?
  • How does this fit with your current state management setup?

(Disclosure: I’m a maintainer. Open to feedback and contributions!)

Top comments (0)