DEV Community

张一凡
张一凡

Posted on

easy-model in Action: Cross-Component Communication, Watching, and Async Loading – All in One Library

Hey guys, state management in React can be a pain: Redux is heavy, Zustand too light, MobX has a learning curve. Today I'm sharing a balanced option: easy-model, a class-based toolkit that simplifies state while adding IoC and watching. Let me show you some real-world scenarios.

Scenario 1: Cross-Component Communication (Instance Sharing)

Wrap your model class with provide to cache instances by args. Components with the same args share state:

import { useModel } from "easy-model";

class CommunicateModel {
  constructor(public name: string) {}
  value = 0;
  random() {
    this.value = Math.random();
  }
}

const CommunicateProvider = provide(CommunicateModel);

function CommunicateA() {
  const { value, random } = useModel(CommunicateModel, ["channel"]);
  return (
    <div>
      <span>Component A: {value}</span>
      <button onClick={random}>Change Value</button>
    </div>
  );
}

function CommunicateB() {
  const { value } = useModel(CommunicateModel, ["channel"]);
  return <div>Component B: {value}</div>;
}
Enter fullscreen mode Exit fullscreen mode

Change in A updates B instantly. Naturally supports "business key" partitioning.

Scenario 2: Fine-Grained Watching (watch & offWatch)

Watch model changes, skip fields for perf:

import { watch, offWatch } from "easy-model";

class WatchModel {
  constructor(public name: string) {}
  value = 0;
  @offWatch
  internalCounter = 0; // Skip watching for perf

  increment() {
    this.value += 1;
    this.internalCounter += 1;
  }
}

const inst = provide(WatchModel)("demo");
const stop = watch(inst, (keys, prev, next) => {
  console.log(`${keys.join(".")}: ${prev} -> ${next}`);
});

inst.increment(); // Only logs value changes
stop();
Enter fullscreen mode Exit fullscreen mode

Great for logging or external sync.

Scenario 3: Async Loading Management (loader & useLoader)

Unified loading states:

import { loader, useLoader, useModel } from "easy-model";

class LoaderModel {
  constructor(public name: string) {}

  @loader.load(true)
  async fetch() {
    return new Promise<number>(resolve =>
      setTimeout(() => resolve(42), 1000)
    );
  }
}

function LoaderDemo() {
  const { isGlobalLoading, isLoading } = useLoader();
  const inst = useModel(LoaderModel, ["demo"]);

  return (
    <div>
      <div>Global Loading: {String(isGlobalLoading)}</div>
      <div>Method Loading: {String(isLoading(inst.fetch))}</div>
      <button onClick={() => inst.fetch()} disabled={isGlobalLoading}>
        Load Data
      </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Wrap-Up

easy-model cuts down boilerplate and mental overhead. In my projects, it simplified complex state logic. Perfect for structured apps.

Check it out: https://github.com/ZYF93/easy-model

What state libs do you use? Ever tried class-based ones? Share below!

Top comments (0)