MVVM and Clean Architecture principles example in React Native
Folder Structure:
- src
- entities
- Task.js
- use-cases
- AddTaskUseCase.js
- RemoveTaskUseCase.js
- interfaces
- TaskRepository.js
- presenters
- TaskListViewModel.js
- components
- TaskList.js
Entities (Task.js)
// entities/Task.js
class Task {
constructor(id, text) {
this.id = id;
this.text = text;
}
}
export default Task;
Use Cases (AddTaskUseCase.js):
// use-cases/AddTaskUseCase.js
class AddTaskUseCase {
constructor(taskRepository) {
this.taskRepository = taskRepository;
}
execute(text) {
const task = new Task(generateUniqueId(), text);
this.taskRepository.addTask(task);
}
}
Use Cases (RemoveTaskUseCase.js):
class RemoveTaskUseCase {
constructor(taskRepository) {
this.taskRepository = taskRepository;
}
execute(taskId) {
this.taskRepository.removeTask(taskId);
}
}
Interfaces (TaskRepository.js):
// interfaces/TaskRepository.js
class TaskRepository {
addTask(task) {}
removeTask(taskId) {}
getAllTasks() {}
}
export default TaskRepository;
Presenters (TaskListViewModel.js):
// presenters/TaskListViewModel.js
class TaskListViewModel {
constructor(addTaskUseCase, removeTaskUseCase) {
this.addTaskUseCase = addTaskUseCase;
this.removeTaskUseCase = removeTaskUseCase;
this.tasks = [];
}
async addTask(text) {
this.addTaskUseCase.execute(text);
this.updateTasks();
}
async removeTask(taskId) {
this.removeTaskUseCase.execute(taskId);
this.updateTasks();
}
async updateTasks() {
this.tasks = await this.taskRepository.getAllTasks();
}
}
export default TaskListViewModel;
Components (TaskList.js):
// components/TaskList.js
import React, { useState, useEffect } from 'react';
import { View, Text, TextInput, Button, FlatList } from 'react-native';
import TaskListViewModel from '../presenters/TaskListViewModel';
const TaskList = () => {
const [newTaskText, setNewTaskText] = useState('');
const [viewModel] = useState(new TaskListViewModel());
const addTask = () => {
viewModel.addTask(newTaskText);
setNewTaskText('');
};
const removeTask = (taskId) => {
viewModel.removeTask(taskId);
};
useEffect(() => {
viewModel.updateTasks();
}, []);
return (
<View>
<Text>Task List</Text>
<TextInput
value={newTaskText}
onChangeText={setNewTaskText}
placeholder="New Task"
/>
<Button title="Add Task" onPress={addTask} />
<FlatList
data={viewModel.tasks}
keyExtractor={(task) => task.id.toString()}
renderItem={({ item }) => (
<View>
<Text>{item.text}</Text>
<Button title="Remove" onPress={() => removeTask(item.id)} />
</View>
)}
/>
</View>
);
};
export default TaskList;
In this example, we’ve created a simple to-do list app that follows MVVM with Clean Architecture principles. The TaskList
the component is the View, TaskListViewModel
acts as the ViewModel, and the Use Cases and TaskRepository
represent the business logic and data access layer.
Remember to add proper error handling, unit tests, and any additional features your application may require as you continue to develop it. This example provides a foundation for organizing your code in a clean and maintainable manner using MVVM and Clean Architecture in a React Native application.