Challenge

I challenged myself to build a Wunderlist clone. Wunderlist is a task management tool, available for all platforms basically. It’s famous for its beautiful & simple UI.

Issues

Wunderlist is a huge app with lots of functionalities, which would take me months to build. I gave myself a couple of days to see how much I could recreate.

1. State management

Rendering a couple of todos is backed by more logic than one might think. Using local states would become really messy. So I used a library for state management to help me with that. But it’s not Redux. No. It’s MobX. In case you don’t know MobX: It solves similar problems like Redux but it’s much simpler. Let’s look at a simple store in MobX:

class TodoListStore {

// creating an observable

@observable todos = []; // computed value to return all the open todos

@computed get openTodos() {

return this.todos.filter(t => !t.completed);

} // add a new todo to the list

@action addTodo(todo) {

this.todos.push(todo);

}

} export default new TodoListStore();

When we want to create a new todo, we call the addTodo method (store.addTodo(todo)). This method adds a todo to the todos observable, and the computed value openTodos updates automatically. All observers (React components) are updated, as well. No need to create a reducer, action, action constants and what else, like in Redux.

2. Swipe functionality

In Wunderlist you can swipe to delete a todo. There are a couple of libraries out there for RN, even in core RN (experimental), providing this feature. However, none of them allow the animation used in Wunderlist, so I modified the code for my needs. I could get close to the original animation, but I’m not satisfied with the outcome, especially not with the performance.

3. Animating the Detail View

When you tap on a todo, a panel slides in with the todo’s data. When I first implemented it, it had serious performance issues. One simple trick helped boosting up the performance of the animation.

// setting state in mobX using observables

// -> re-renders the appropriate views

this.selectedTodo = todo; // bad: starting the animation immediately

this.openDetailView(); // good: calling the animation asynchronously

setTimeout(this.openDetailView.bind(this), 0);

When you feel animations aren’t smooth enough, you can use this trick in your app, as well. To see the difference, check out the following gifs: