- Published on
Building a React Application with MVVM Pattern
![Building a React Application with MVVM Pattern](https://user-images.githubusercontent.com/33494971/269602373-9aa20fcb-72ca-49ca-902c-e5866a74bf0e.png)
Building a React Application with MVVM Pattern
Building a React Application with Custom EventEmitter and MVVM Pattern
In this article, we'll dive into a powerful architectural pattern that combines modern JavaScript, React, and a custom implementation of an EventEmitter to manage state changes in a reactive and efficient manner. This approach leverages the Model-View-ViewModel (MVVM) pattern, traditionally used in frameworks like Angular and Vue, and adapts it to React applications. The MVVM pattern can enhance your project's structure by providing a clear separation of concerns, which simplifies management and improves scalability.
Setting Up the Environment
To begin, ensure Node.js is installed on your machine. We'll start a new React project using Create React App:
npx create-react-app react-mvvm-demo
cd react-mvvm-demo
npm start
Creating a Custom EventEmitter Class
Our first step is to create a custom EventEmitter
class. This class will manage event subscriptions and notifications:
class EventEmitter {
constructor() {
this.events = {};
}
on(eventName, listener) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(listener);
}
off(eventName, listener) {
if (!this.events[eventName]) {
return;
}
this.events[eventName] = this.events[eventName].filter(
(l) => l !== listener
);
}
emit(eventName, data) {
const event = this.events[eventName];
if (event) {
event.forEach((listener) => {
listener(data);
});
}
}
}
Extending UserModel with EventEmitter
Next, we extend this EventEmitter
to create a UserModel
class. This model will manage user data and emit updates whenever the user list changes:
class UserModel extends EventEmitter {
constructor() {
super();
this.users = [];
}
addUser(user) {
this.users.push(user);
this.emit("update", this.users);
}
getUsers() {
return this.users;
}
}
Building the React Component
We then build a React component that listens to updates from our UserModel
:
import React, { useEffect, useState } from "react";
const userModel = new UserModel();
const UserComponent = () => {
const [users, setUsers] = useState(userModel.getUsers());
useEffect(() => {
const handleUpdate = (newUsers) => {
setUsers([...newUsers]);
};
userModel.on("update", handleUpdate);
return () => userModel.off("update", handleUpdate);
}, []);
const handleAddUser = () => {
userModel.addUser({ name: "New User", id: Date.now() });
};
return (
<div>
<button onClick={handleAddUser}>Add User</button>
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
};
export default UserComponent;
Integration into App.js
Finally, we integrate our UserComponent
into the main App component to display it within our application:
import React from "react";
import UserComponent from "./UserComponent";
function App() {
return (
<div className="App">
<h1>User Management</h1>
<UserComponent />
</div>
);
}
export default App;
Conclusion
In this blog, we've successfully implemented an MVVM pattern in a React application using a custom EventEmitter
class. This architecture not only provides a clean separation between the application's logical and presentation layers but also enhances the scalability and maintainability of the code. By creating a decoupled system where components communicate through events, developers can build more flexible and manageable applications.
Potential Use Cases
- Real-time Applications: Ideal for scenarios requiring real-time updates like chat apps or live sports scores.
- Complex UIs: Simplifies communication in complex interfaces, avoiding prop drilling and callback chains.
- Server-side Events: Can integrate seamlessly with server-side push technologies like WebSockets for reactive updates.
Using a custom EventEmitter with React opens up a realm of possibilities for crafting sophisticated web applications that are both robust and easy to maintain.