In modern frontend development, Domain-Driven Design (DDD) is gaining traction as a preferred approach. The easy-model framework, with its unique model-driven architecture, offers developers a convenient way to implement DDD. This article highlights how easy-model facilitates domain-driven development, enhances testability, and remains simple to use.
Convenient Domain-Driven Development
At the heart of easy-model is model class encapsulation. Each model class represents a business domain, encapsulating state and logic, avoiding the fragmentation of traditional state management. This design centralizes business logic, making it easy to understand and maintain, perfectly aligning with DDD principles.
import { useModel } from "easy-model";
class UserDomain {
user = { id: "", name: "", email: "" };
constructor(initialUser = { id: "", name: "", email: "" }) {
this.user = initialUser;
}
updateUser(newUser: typeof this.user) {
this.user = { ...this.user, ...newUser };
}
validateEmail() {
return this.user.email.includes("@");
}
}
function UserComponent() {
const userDomain = useModel(UserDomain, [{ id: "1", name: "John Doe", email: "john@example.com" }]);
return (
<div>
<h2>{userDomain.user.name}</h2>
<p>Email valid: {userDomain.validateEmail() ? "Yes" : "No"}</p>
<button onClick={() => userDomain.updateUser({ name: "Jane Doe" })}>
Update Name
</button>
</div>
);
}
With useModel, components directly create and subscribe to model instances. Model class methods encapsulate business logic, such as validation and updates, ensuring domain knowledge cohesion. Compared to Redux's action/reducer separation, easy-model is closer to OOP thinking.
Superior Testability
easy-model comes with built-in Vitest support, making testing intuitive and efficient. Model classes as pure logic units are ideal for unit testing, without complex mocking.
import { describe, it, expect } from "vitest";
describe("UserDomain", () => {
it("should validate email correctly", () => {
const model = new UserDomain({
id: "1",
name: "Test",
email: "test@example.com",
});
expect(model.validateEmail()).toBe(true);
model.updateUser({ email: "invalid" });
expect(model.validateEmail()).toBe(false);
});
it("should update user", () => {
const model = new UserDomain({
id: "1",
name: "Old",
email: "old@example.com",
});
model.updateUser({ name: "New" });
expect(model.user.name).toBe("New");
});
});
The framework's instance caching mechanism (provide) allows grouping by parameters, ensuring test isolation. Dependency injection via the inject decorator and container configuration supports mock replacements, improving integration test efficiency.
Simple and Easy-to-Use Experience
easy-model eliminates complex configurations—install and use immediately. Strict TypeScript mode ensures type safety, preventing runtime errors. The API is clean, requiring only a few hooks to get started.
Seamless React integration:
import { useModel, useWatcher } from "easy-model";
function CounterComponent() {
const counter = useModel(CounterModel, [0, "Counter"]);
useWatcher(counter, (keys, prev, next) => {
console.log(`Field ${keys.join(".")} changed from ${prev} to ${next}`);
});
return (
<div>
<h2>{counter.label}</h2>
<div>{counter.count}</div>
<button onClick={() => counter.decrement()}>-</button>
<button onClick={() => counter.increment()}>+</button>
</div>
);
}
Asynchronous operations use the @loader.load decorator, with the useLoader hook for querying states, simplifying loading handling. @offWatch optimizes performance by avoiding unnecessary watching. Cross-component sharing is achieved through provide and useInstance.
Performance and Scalability
easy-model uses Proxy for deep change detection, supporting nested objects and reference relationship changes. The watch function allows listening in non-React environments, while useWatcher handles component side effects. The IoC container supports namespace isolation, facilitating management in large applications.
Compared to Redux/MobX, easy-model reduces boilerplate and boosts development efficiency. The benchmark example shows competitive performance.
Conclusion
easy-model centers on models, perfectly supporting domain-driven development. Its class encapsulation boosts testability, and its clean API ensures ease of use. Whether for small projects or complex applications, it significantly improves development efficiency.
Try easy-model today for a more elegant frontend development experience! Project repo: GitHub
Top comments (0)