Building a Wunderlist Clone

React Native UI Challenge #2

Here it is, my second React Native challenge. In case you missed the first one, go check it out first!

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:

before (left) vs after (right)

4. Editing the title

OK, so editing the title of a todo shouldn’t be hard, right? Wrong. Somehow, it’s not straightforward to automatically grow a text input. One has to listen to contentSize changes and save the height as a state and then set the height dynamically. After implementing this hack/trick, the result was not satisfying, though. You can see what I mean by watching this gif:

Notice the jump

5. Ordering todos

There is actually some logic hidden behind the order of the the todolist: (1) Newly created todos are added on top. (2) When you “star” a todo, it moves to the top. (3) Completed todos are ordered by the completion date, newest on top. (4) When “unchecking” a todo, it will be appended to the bottom.

Order of todos

How I solved it: Every todo has a position attribute and the todo-list store keeps track of the lowest and highest positions using MobX’ computed values functionality. So for example when a todo is created or starred it gets the current highest position + 1.

Result

Don’t forget to try it out at Exponent! And of course all the code is available on Github. 😊


Hey! My name is Yousef and I’m doing UI challenges in React Native. The idea is to recreate UI designs from Dribbble screenshots and popular apps using React Native. If you like it, please hit the ❤️ button and follow me for more challenges!