Arpith Siromoney 💬

Small steps to speed up a React Native app

I’m building an app to share notes called Constellational (sign up!), and a major part of this is displaying posts in a React Native ListView. I made some small changes today make the app faster.

Move stuff out from loops

This is the code that gets called when the flux store changes, it gets the posts and checks if they have unpublished edits saved locally:

getAll() {
 var posts = PostStore.getAll();
 posts = posts.map((post) => {
   var unpublishedEdits = EditStore.get(post.id);
   if (unpublishedEdits) {
     post = unpublishedEdits;
     post.hasUnpublishedEdits = true;
   }
   return post;
 });
 return posts;
}

As always, moving stuff out of the loop improved performance:

getAll() {
 var user = PostStore.getUser(this.props.username);
 var posts = user.posts.map((url) => {
   return PostStore.getPost(this.props.username, url));
 });
 var edits = EditStore.getAll();
 posts = posts.map((post) => {
   if (edits[post.id]) return edits[post.id];
   else return post;
 });
 return posts;
}

The function now makes only one request to the EditStore (the flux store that keeps track of unpublished edits). Also note that I’ve changed the way posts are accessed from the PostStore.

Run less JavaScript

The PostStore’s getAll() used to look like:

function getAll(username) {
 if (!username) username = SettingStore.getUsername();
 if (!_users) {
   loadAsyncStore()
     .then(fetchFromServer)
     .then(updateAsyncStore)
     .then(retryFailedRequests);
   return [];
 } else if (!_users[username]) {
   fetchFromServer(username).then(updateAsyncStore);
   return [];
 } else {
   return _users[username].posts.map((url) => {
     return _posts[username][url]
   });
 }
}

This has now been replaced with:

function getPost(username, postURL) {
 if (!username) username = SettingStore.getUsername();
 if (!_posts) {
   loadAsyncStore();
 } else if (!_posts[username] || !_posts[username][postURL]) {
   fetchPost(username, postURL);
 } else {
   return _posts[username][postURL];
 }
}
function getUser(username) {
 if (!username) username = SettingStore.getUsername();
 if (!_users) {
   loadAsyncStore().then(() => fetchUser(username));
   return {posts: []};
 } else if (!_users[username]) {
   fetchUser(username);
   return {posts: []};
 } else {
   return _users[username];
 }
}

Why is this faster? When the PostsPage component is loaded a bunch of calls to getAll() were being made — which resulted in fetchFromServer() running several times. This kept the JavaScript thread busy while fetchFromServer() downloaded all the posts. Meanwhile, the ScrollView worked fine (this is handled on the iOS side of things). There is a noticeable difference now, because fetchFromServer’s replacement only makes a single request. This fixes #57.

#56 is fixed as well, because local storage is updated when a post is fetched.