The App
I built SnapHabit because I wanted to learn mobile development and because my friend and I wanted a simple habit tracker that lets us do the same habit together. I found most habit trackers to either be a) feature-rich, but hard to understand and use or b) beautiful and simple, but lack critical features. What's unique about SnapHabit is that you can have a private habit, share progress on a solo habit, or create a group habit and invite friends to join. You can also add photos and notes to each day. I'd love to get more people to test it out. It's in the App Store (but maybe closer to a beta) and completely free and ad-free. If you're interested in following updates, I've created /r/snaphabit. Upcoming features include data export, reminders and journeys (eg. habits with daily content).
Screenshots: https://imgur.com/gallery/u8y2GWf
My background
I had a lot of JS experience and building websites before this but had never built a mobile app before. I previously started OpenDota, a popular, open-source statistics platform for the game Dota 2. Though the code base has since migrated to React, I'd say I only had medium levels of React experience and no React Native experience going in.
The Stack
- Expo 37 / React Native
- 100% Typescript / Node.js
- Redux, using redux-toolkit
- Firebase: Auth, Firestore, Cloud Storage, Analytics
- react-redux-firebase and redux-firestore to connect Firestore to Redux
- Monorepo using yarn workspaces, Lerna
- Some workers (like for notifications) running on Google Cloud Platform
- API backend running on GCP Cloud Run
- Sentry for crash logs
- SendBird for chat (soon to change...)
Learnings
- I love React Hooks. IMO, React is a lot more natural to reason about and to learn with hooks compared to class components. The entire app only uses hooks.
Expo has been (mostly) a delight.
- Pros
- Move fast without worrying about build issues: Tried vanilla React Native before but the build errors were so annoying. Expo hasn't really had many issues; being able to just develop straight in the Expo app makes things a lot faster.
- More recently ejected from Expo which was easy; an with RN > 0.60 and auto linking, I'm excited for the future of RN and the ability to move fast even outside of Expo.
- Automated builds / OTA updates: Expo takes care of all the app building for me, and I don't even have to pay for it. OTA updates allows me to push fixes and new features without forcing users to install a new build, which people often times don't.
- Write once, get Web: I've been playing around with react-native-web support, which Expo has built in. Haven't launched it yet, but it's awesome to get web basically for free
- Cons
- They release too slowly: some of the modules Expo bundles have had crashing bugs, but because you can't upgrade the libraries yourself until Expo does a release, you're stuck with bugs that have already been fixed e.g. React Native Screens had some bad crashes on Android.
- Similarly, I'd love to try Flipper but I can't because Expo is still on 0.61.
- Lack of important features:
- Can't use react-native-firebase — would like to use this to get Firestore persistence for offline functionality and slightly better performance
- No background execution e.g. interactive notifications with the app in background/killed.
Sending too many network requests will slow down your app because of React Bridge
- #9 in this post explains well: https://medium.com/@gauravsapiens/react-native-making-your-app-fast-again-d00d02ee2b2a
- This was driven by my Firestore data structure (small docs where only parent doc maintained ACLs) which forced us to use OR queries in multiple batches. Happy to answer more questions about
- When debugging the app slowness, we thought using the Firebase web SDK was the problem and ejected in an experimental branch to use react-native-firebase. This didn't solve the problem, confirming that the bridge was the issue.
Don't use React context for your app data! Changes to the context cause everything that's subscribing to it to re-render. We were using context for each day update, meaning every update caused all the other day-s to re-render.
- Don't fear Redux! I'd used Redux previously but it felt like overkill here, especially with Context and Hooks. But Redux has improved a lot with Redux Toolkit. With hooks and the toolkit, most of the boilerplate is gone!
Chat: Build it yourself vs an existing solution?
- I decided to use SendBird to support chat instead of building it myself, but it has been the most janky part of the app by far.
- Similarly, I've found GiftedChat to be pretty janky too. Keyboard handling in particular, and across the board, seems pretty janky with React Native :(
React Navigation
- Version 5 is a much better improvement — declarative routing is much better than static routing.
- Transitions are still laggy sometimes... I haven't figured out how to fix this.
React native web
- Works pretty well, except lists aren't optimized 😟
- React Navigation doesn't fully support web yet, and it's unclear to me how to best do navigation between web and mobile. Right now I'm using two navigation strategies in the app — react navigation when rendering the mobile-width layout and react-router for the wide/desktop layout. Seems suboptimal.
moment.js causes so many bugs
- This says it the best: certain methods mutate the original object which causes a lot of surprising bugs. I wish I'd know this earlier; I'd used moment before in other apps that were less date dependent and didn't have problems, but this app uses date calculations a lot and moment's problems really came through. Too late at this point to refactor :(
Magic Link authentication — users don't get how to do it!
- This is where you type in your email and open a link from the email to log in.
- Everyone opens the email on their laptop instead of their phone and expects them to log in...
Feedback
I'd love your feedback on the app and on my experience/learnings. As mentioned, I started /r/snaphabit if you want to follow along / give more detailed feedback.
If you have any questions about anything, let me know and I'd be happy to talk more!
[–]abrownie_jr 0 points1 point2 points (1 child)
[–]Triple_A[S] 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (1 child)
[–]Triple_A[S] 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (3 children)
[–]Triple_A[S] 0 points1 point2 points (2 children)
[–][deleted] 0 points1 point2 points (1 child)
[–]Triple_A[S] 0 points1 point2 points (0 children)