In e-commerce application development, modules like product management, shopping carts, and order processing often involve complex business logic. easy-model's model-driven architecture can effectively organize this domain knowledge, improving code maintainability. This article demonstrates how to implement domain-driven development in e-commerce using easy-model through real-world examples.
Product Management Model
Products are the core domain in e-commerce. We can create a ProductModel to encapsulate product state and business logic:
import { useModel } from "easy-model";
class ProductModel {
product = {
id: "",
name: "",
price: 0,
stock: 0,
category: ""
};
constructor(initialProduct: typeof this.product) {
this.product = initialProduct;
}
updateStock(newStock: number) {
if (newStock < 0) throw new Error("Stock cannot be negative");
this.product.stock = newStock;
}
isAvailable() {
return this.product.stock > 0;
}
applyDiscount(discountPercent: number) {
this.product.price *= (1 - discountPercent / 100);
}
}
function ProductCard({ productId }: { productId: string }) {
const productModel = useModel(ProductModel, [{
id: productId,
name: "iPhone 15",
price: 5999,
stock: 10,
category: "Electronics"
}]);
return (
<div>
<h3>{productModel.product.name}</h3>
<p>Price: ${productModel.product.price}</p>
<p>Stock: {productModel.product.stock}</p>
<p>Status: {productModel.isAvailable() ? "In Stock" : "Out of Stock"}</p>
<button onClick={() => productModel.updateStock(productModel.product.stock - 1)}>
Buy
</button>
</div>
);
}
This model encapsulates product business rules like stock management and discount application. Domain logic is centralized, avoiding scattered business code in components.
Shopping Cart Shared State
In e-commerce apps, shopping carts need to be shared across multiple components. easy-model's provide mechanism naturally supports instance caching grouped by user:
import { provide, useInstance } from "easy-model";
class CartModel {
items: Array<{ productId: string; quantity: number }> = [];
userId: string;
constructor(userId: string) {
this.userId = userId;
}
addItem(productId: string, quantity: number) {
const existing = this.items.find(item => item.productId === productId);
if (existing) {
existing.quantity += quantity;
} else {
this.items.push({ productId, quantity });
}
}
getTotalItems() {
return this.items.reduce((sum, item) => sum + item.quantity, 0);
}
}
const CartProvider = provide(CartModel);
function CartIcon() {
const cart = useInstance(CartProvider("user123"));
return <div>Cart ({cart.getTotalItems()})</div>;
}
function AddToCartButton({ productId }: { productId: string }) {
const cart = useInstance(CartProvider("user123"));
return (
<button onClick={() => cart.addItem(productId, 1)}>
Add to Cart
</button>
);
}
Through provide, different components share the same cart instance, grouped by user ID, ensuring data consistency.
Order Asynchronous Processing
Order submission involves asynchronous operations. easy-model's @loader.load decorator simplifies loading state management:
import { loader, useLoader, useModel } from "easy-model";
class OrderModel {
order = { id: "", status: "pending", items: [] };
constructor(orderId: string) {
this.order.id = orderId;
}
@loader.load(true)
async submitOrder() {
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 2000));
this.order.status = "confirmed";
}
}
function OrderForm() {
const orderModel = useModel(OrderModel, ["order123"]);
const { isLoading } = useLoader();
return (
<div>
<p>Order Status: {orderModel.order.status}</p>
<button
onClick={() => orderModel.submitOrder()}
disabled={isLoading}
>
{isLoading ? "Submitting..." : "Submit Order"}
</button>
</div>
);
}
useLoader automatically tracks async method states, no manual loading boolean management needed.
Test-Driven Development
easy-model's model classes are easy to test, ensuring business logic correctness:
import { describe, it, expect } from "vitest";
describe("ProductModel", () => {
it("should update stock correctly", () => {
const model = new ProductModel({
id: "1",
name: "Test",
price: 100,
stock: 5,
category: "Test",
});
model.updateStock(3);
expect(model.product.stock).toBe(3);
});
it("should throw on negative stock", () => {
const model = new ProductModel({
id: "1",
name: "Test",
price: 100,
stock: 5,
category: "Test",
});
expect(() => model.updateStock(-1)).toThrow();
});
});
Unit tests cover business rules, improving code quality.
Conclusion
easy-model shows great strength in e-commerce applications: model encapsulation of domain logic, provide for state sharing, @loader.load for async handling. Combined with Vitest testing, ensures high-quality delivery. Try easy-model for more elegant e-commerce development!
Project repo: GitHub
Top comments (0)