DEV Community

RayedDev
RayedDev

Posted on • Edited on

2

Clean React MVVM inspired by Apple SwiftUI

I used to develop web apps using React for a long time and as recently I had to work with IOS Mobile development team inside my company helping to port web application to IOS and I noticed the Apple SwiftUI framework, indeed it is heavily inspired by React.js as data and state driven rendering technique, and it does apply MVVM architecture that i find a very clean approach, therefor I decided to cheat 🙂

So let's first look at simple plain SwiftU implementation of MVVM and see how clean it look

// Model
struct Task {
    var id: UUID = UUID()
    var title: String
    var complete: Bool
}

// ViewModel
class TodoManagerViewModel: ObservableObject
{
    // value publishers (publish change to view state and force view render)
    @Published var tasks: [Task] = []

    func addTask(title: String)
    {
        tasks.append(Task(title: title, complete: false))
    }

    func complete(id: UUID)
    {
        for i in tasks.indices
        {
            if tasks[i].id == id
            {
                tasks[i].complete = true
            }
        }
    }

    func clear()
    {
        tasks.removeAll()
    }
}


struct ContentView: View {
    // Observe ModelView and request render
    // if any @Published variables changed
    @StateObject var todoManger = TodoManagerViewModel()



    var body: some View {
        // Render logic same as
        // React Components composition style
        return AnyView()
    }
}
Enter fullscreen mode Exit fullscreen mode

and by compiling this code we get this app

Image description

So the key design points is:

  • ViewModel with @Published properties
  • attach the ViewModel to the View to receive published changes.

Now let us construct the same design using Reactjs

I built this typescript module to help us construct a ViewModel and publish it state .

react-mvvm-like

now let us see how we can build MVVM react TodoManager application with this module the same way as Apple SwiftUI do.

1) install react-mvvm-like

2) creating Task Model with autoDoneAfter property so task gonna flip to done after a few seconds if not done by user.

export type Task = {
id: string;
title: string;
done: boolean;
autoDoneAfter: number; // seconds
interval: number;
};

3) construct the ViewModel class extending ObservableObject
and define published properties

import { Published, ObservableObject } from "react-mvvm-like";
export class TodoViewModel extends ObservableObject {
@Published tasks: Task[] = [];
async fetch() {
...
}
intervalToggle() {
...
}
removeTask(task: Task) {
...
}
addTask(title: string, done: boolean = false) {
...
}
toogle(task: Task, compelete?: boolean) {
...
}
doneAll() {
...
}
pushToServer() {}
}

4) receive the changes inside React Component.

import { useObservedObject } from "react-mvvm-like";
const todoViewModel = new TodoViewModel()
export default function Component() {
const todoManager = useObservedObject(todoViewModel);
useEffect(() => {
todoManager.fetch();
}, []);
return (<ul>
{todoManager.tasks.map(t => {
return <li key={t.id}>{t.title}</li>
})}
</ul>)
}

thats it, we are done, please check full example below:

If you have any feedback on this article, please let me know!

Retry later

Top comments (0)

Retry later
Retry later