Peachy: A Social Network made in React Nativecalendar_today Posted 12 months ago · 8 minute-read · Showcase
I wanted to build kind of a social network for mobile, but with a twist: you needed to chat with somebody for a while to be able to view their profile picture and information.
I thought about all the features the app would have:
- Typical login, registration, account recovery pages.
- A place to “Discover” people that are already on the platform, through cards (Tinder-like aesthetics).
- A real-time chat to be able to communicate with people you met from the “Discover” page.
- User location handling to show cards from people that are near the user.
- A “flagship” feature: Unlocking user profile information gradually by engaging in conversation.
The idea was to make the app cross-platform. I knew how to build Android apps, but I felt like learning a new framework this time. I also have little to no experience with iOS development.
I found out about React Native, but the chances I’d choose it for development were very slim: I didn’t know anything about React, and that meant I had to learn React and its ecosystem, how to “think in React”, and then learn React Native.
We didn’t really have much time for the project either, about a month. And I wanted to bake a fully-working social network, along with its documentation.
I finally decided to learn React Native and build the whole app with it. Woohoo! 🎉
Getting to work! 🛠
I had to decide which libraries I was going to use for the React Native client though, which wasn’t an easy task. I ended up choosing the following:
- MobX for State Management. I didn’t really understand Redux at the time so I went towards the more familiar object-oriented approach with Mobx. Nowadays all I can use is Redux 🤣.
- React Navigation for UI navigation.
- Native React WebSocket APIs for the real-time chatting experience.
- Native React Fetch API for communicating with the backend.
- rn-firebase for Push Notifications, a very important feature in this app.
Here are the libraries I used for my Node.js backend:
- Express.js for building the API: Database <=> Express API <=> React Native REST Client.
- Mongoose ORM for MongoDB. I thought Mongo would be the best choice for this project since it’s a fast-paced app, lots of database writes in short time-spans, and that is where Mongo excels.
- A reverse geocoder to find out the users location on country and city levels. The backend receives the user’s coordinates obtained from the React Native client and returns the user’s city, country, timezone, and other useful info. This worked with great accuracy (and is free!) but was very CPU-intensive. This ended up being a bottleneck − my server at the time wasn’t that powerful.
wspackage for duplex WebSocket communications.
Figuring out the authentication flow 🍃
So, I had all my libraries sorted out, and now I had to sort out the app’s architecture − deciding how it was going to work as a whole.
Authentication is one of the first things that, in my opinion, you must sort out at the beginning of any development. There were essentially two parts to protect in this app: A REST API-driven part, and a real-time, WebSocket-driven part. The client had to be authenticated on both communication channels for the app to be secure. Here’s how I did it:
- User opens the app and immediately starts a WebSocket connection to the server, which will return a uniqueID to identify the client and its socket.
- User logs into the app. The REST client asks the server for a JSON Web Token (JWT) with a default expiration time of 6 hours.
- The server authenticates the client’s socket with the generated JWT and returns a response to the REST Client with it.
- Now the client can receive messages from the server through a fully authenticated bi-directional WebSocket connection and can access the protected resources of the Express REST API server.
- The client persists the JWT in the mobile phone’s storage for future use until expiration.
Once authenticated with a valid, non-expired JWT, a client could then access protected resources, and receive real-time data.
Here’s an example of real-time chatting using Peachy’s architecture, given two users React Native Client 1 and React Native Client 2:
Designing the database 🤔
The database design was pretty straight-forward:
It basically had 5 entities:
- User: Represents a user of the app, ONLY contains the necessary data for the user to authenticate itself.
- Profile: The user’s profile. I wanted to separate this entity and not just stick it in the user entity because I had planned to allow users to delete their profiles. Profiles contained the user’s real name, interests, skills, and the location: latitude, longitude, timezone, and city. Latitude and longitude were obtained from React Native APIs, timezone and city were completed from the backend’s reverse geocoder.
- Message: Represents a message with sender, receiver, and body. Also contains a read-receipt, a boolean field that indicated if the receiver had read the message or not.
- Post: Posts created and tagged by users, that appear in the “Discover” screen for people to swipe through. Card content could be about anything.
- Bookmark: I had planned to let users bookmark their favorite cards, or save them for later. This was not implemented in the end.
Building the UI 🤤
OK. So with all this laid out, I was ready to work on the React Native client! The most exciting part, building the visuals, right?
Before really diving into the delicate art of building the apps visuals, I had to think about the navigation flow. Another really important point of any app. The way the user navigates through your app will determine how fluid and overall “nice” your apps feel.
Each card is a screen, and the arrows show how a screen can be accessed (through UI components like buttons, the drawer, tabs, etc…).
I kept tinkering with this navigation flow until I felt it was “just right”, I first tried setting up the navigators with empty screens, before designing anything.
With the navigation flow sorted out, we can start building the UI, right?
Before designing and implement ANY screen, I had to decide how I was going to organize these screens in the apps folder structure. As with the navigation flow, I tried out different folder structures until I was happy with it:
- android: Native Android files.
- ios: Native iOS files.
- Assets: Images, sounds, etc.
- Components: Individual UI components. Each have their own folders with declarative React UIs and stylesheets.
- Containers or Screens. Each have their own folders with declarative React UIs and stylesheets.
- Stores: MobX data stores. Interacted with WebSockets and REST API.
- Services: Classes to consume external services, such as Push Notifications, etc.
- i18n: Internationalization files.
- Navigation: The navigator configurations: DrawerNavigation, StackNavigation, and TabNavigation.
Fairly simple to find and modify anything from the get-go.
At this point, I was ready to design each and every screen in the app. It was the only thing left — I had sorted out everything in the backend, and had planned out what I wanted to do with the client.
Believe me, by doing the backend first, building app screens was a walk in the park. I knew what part of the API each screen was going to use, and with MobX there wasn’t much to think about in terms of state management.
I used Adobe XD for prototyping the app in a very simple manner, and then went one by one implementing each screen.
And more… Here’s the full, high-res album of most of the screens:
My final thoughts
So… I was able to finish my app in time, and the project got a pretty good grade. Nonetheless, the grade wasn’t that important to me. I was just happy that I was able to learn a new framework, and think out, design, and build a complete mobile app in just a month. I kinda then realized I was made for this.
The presentation and demo went great, I actually had no oopsies! that I can remember. 😜 And that’s a huge achievement for me since I get nervous about anything…
Oh yeah, I also made and wore my own merch to the presentation. You know what they say… GO BIG OR GO HOME. And boy, did I go big:
Anyway, I hope you found this post interesting. I felt like sharing this experience today with you all.
Wish you the best!