React Native Architecture at Product Hunt

Rate this content
Bookmark

I'm going to showcase the React Native architecture we use in our new mobile app at Product Hunt. What we learned, among the way. How we moved what we know from web to mobile. Topics will be designing reusable React components, GraphQL, routing in the app, application lifecycle, keyboard controls, toast messages, and others.

18 min
14 May, 2021

Video Summary and Transcription

The speaker discusses their React Native architecture and how they structured their app, choosing React Native over native development due to limited resources and the need for UI experimentation. The architecture consists of support, components, and screens, with a focus on code organization and extensibility. The speaker explains the screen creation process, including the use of React Native Navigation and a state machine pattern. They also highlight the use of GraphQL for data retrieval and navigation between screens. The talk covers the structure of common components, utilities for styling, and support for dark mode. Overall, the speaker emphasizes the importance of isolating dependencies and utilizing a directory structure approach.

1. Introduction to React Native Architecture

Short description:

Hello, everybody. My name is Radoslav Stankov, and I'm coming from Bulgaria. Today I'm going to talk about our React Native architecture and how we have structured our React app. Produhunt is this website. When we decided to rebuild our mobile app, we had two choices: go native with Swift or go React Native. We had a terrible experience with React Native in the past, but we only had two developers with Swift experience and no Android experience. We also needed to do UI experimentation and support Android, so we chose React.

Hello, everybody. My name is Radoslav Stankov, and I'm coming from Bulgaria. I'm here in Bulgaria, sitting right now. And I'm head of engineering at Produhunt.

And today I'm going to talk a bit about our React Native architecture and how we have structured our React app. But before we get into the technical details, for every good architecture, you have to get the context, like where the team is coming from, what the requirements are, and how the stuff is built.

So Produhunt is this website. This is how we look on the web. And I have given previous presentations around the Produhunt architecture. I won't go into details there. But when we decided to rebuild our mobile app early this year, actually we released it this year, we started a bit later than that. We were wondering, OK, now we should do a big reboot into our mobile app. And for our cases, we have basically two choices.

One was go native with Swift, and the other was go React Native. We really had really terrible experience around more than two years ago when initially we started with React Native. It was quite a bit of a challenge. On the other side, we have only two developers who have some Swift experience, not very new ones, and we have zero developers with Android experience. And our app really needed to run on Android, as well. Also, Apollo, so we use GraphQL for all our data transferring and the best way to use it is Apollo, in my opinion. Apollo for Swift is not as good as Apollo for JavaScript. And our team already knew how to deal with React and Apollo. The other thing we needed for this app was to do a lot of UI experimentations, and again, we also needed Android.

So early in 2020, we were making mobile app experiments for YourStack. So early in 2000, we worked on two apps for a couple of our products and experimentation. One was YourStack, the other was called StackCamp. They were both not released because they were just embedded. We tested some ideas there. So, yeah, don't tell anybody. So from them, we were able to compare the ecosystems from React and Swift. And we decided to go with React just because we needed Android.

2. React Native Architecture Overview

Short description:

Our team already knew React Native and decided to use it along with GraphQL and Apollo. We prioritize making common operations easy, organizing code, isolating dependencies, and ensuring extensibility and usability. Our architecture consists of three pillars: support, components, and screens. The directory structure of our mobile app reflects this architecture. We start with the top layer, the screens, which are defined in the app GS and utilize React Native Navigation.

Our team already knew React Native, and React Native actually became a lot better than two and a half years ago. It got a lot faster, a lot more stable, and we didn't have the same issues as we had before. And the tech stack we decided to go was, okay, we go with React and React Native. We use GraphQL, we access it through Apollo. And the table steaks, TypeScript Jest and Pretier are basically not a question if we go with the JavaScript ecosystem. And everything done mobile, we are using Fastlane for tooling.

So the things around architecture is, if you don't know where to start, you can very easily get into the situation where you get stuck. So we want to move fast and have breakfast, not breaking things fast. So we want to move. So for our architecture, we have four goals. First is to make the common operations easy so the engineers can easily add new things. Then we need to put code organization so we can onboard new team members very easily into the code base. Isolate dependencies, like in the JavaScript world and in basically every modern world where we're dealing with external dependencies and they can very easily get out of sync, out of date and break a lot of things without our control. And the final thing is extensibility and usability. We want to build things that we can extend and reuse over time. But the most common thing for us is to make the common operations easy so everything a developer has to do every day should be very easy for them.

The way I'm thinking about the parts of the architecture, I'm seeing three pillars. The support, the components and the screens. And they look like that in my head. We have a big support area which helps us build the core reusable components and then we build the screens on top of that. So for somebody more usual, this is the way you can imagine it. You have the pilots, you put them in the lines and they make Voltron and make it really nice. So if you go and see our directory, this is how the directory structure of the mobile app looks. And it represents the architecture of this app. And if you see, if I color code it here, we have support, components and the screens.

So again, talk chip, show me the code. So let's start with the top layer because it actually helps us understand the layers of both if we start reverse. From the screens. So all the screens are defined in the app GS. And here, what we do is we use the react native navigation.

3. React Native Screen Creation and Structure

Short description:

We experimented with different navigation options, but React Native Navigation fit our working style the best. Our main screen consists of a main stack that attaches the screens. The screens are organized in a screens folder, and each screen is exported from an index file. Each screen has its own directory, which includes private components, a graph query for data retrieval, utilities, and the index JS file. Screens follow a state machine pattern, starting with a layout, transitioning to a loading state, and handling error and loaded states. We extracted a utility called CreateScreen to simplify screen creation by defining the screen's name, query, query variables, component, and type.

We experiment with the others navigation, but this one was the one that fit our working style the best. It's a really good library and we didn't have almost any issues with it.

So this is how our main screen looks like, like a summarized version of it. So we have this main stack that we are attaching the screens. And notice that here we are just doing a spread on the screens. So the spread of the screens, the screens come from this screens folder and it's in index, what we do is we just export all the different screens. So we have a central place where a developer can actually trace where their screen is. It's like a map and for screens, this is how a screen looks like.

We basically have a flat list to where, on the root we have the screen name. Then we have a directory where we have everything related to the screen. Like for example, in this screen, we have two private components, which search and the fit item. So those are components only used in the screen. We have the graph query, the query that will get the data for the screen. We have some utilities and the index JS is the screen.

If we think about the screen, the screen is actually a state machine and this state machine starts with a layout. Then it goes to the loading state inside of this layout. If something bad happens, there is an error state and this error can be a server error, not found error, authorization, authentication, and similar errors. On the other side, we can have the loaded state. So when the screen is loaded, there is a couple of operations we always need to do. We need to render the screen. And we notice that we have a lot of this state code in our system.

So what we did was we extracted an utility we have on the web called CreateScreen. And this CreateScreen allows us to define, okay, what's the name of the screen? So it's very good, useful for debugging. What's the query, which would be used to go to the data. What are the query variables for this query? Which is the component this screen is going to render, and we just pass with this component the data and the params. What type of screen is this? In our application we have three types of screen. We have a screen which is like push screen, which we just push it back. We have an action sheet, which just opens like an action sheet. And we have an overlay, which is an overlay. Also there is a couple of other options like the screen background.

4. React Native Screen Creation and Navigation

Short description:

Different screens in our system have different backgrounds and titles in the navigation. We handle different screens by using a create screen command. Our app architecture involves screens, queries, components, and hooks. GraphQL connects everything in our app, providing type safety and the ability to nest fragments. We also utilize a cool trick called routes, which allows easy navigation between screens.

Different screens in our system has different backgrounds, what's the title in the navigation. And there is this safe area, which is the iPhone X style of no home button. And how do we do in different screens? So every developer can just build a screen with calling this command.

So what we have is we have the screen, which is create screen, it goes through the screen index and then goes through the app. And here's an example screen. This is kind of the home screen we are having. We just have a query with its variable. And then we have the component and we use two hooks to set up the live navigation. We set up the push notifications and we render an infinite scroll of items. And again, GraphQL is the thing which also connects everything in our app. So in the backend, we use Rails and we export the GraphQL. The GraphQL goes to Apollo and Apple will help us generate TypeScript. So using the Apollo code gen, we can take the fragments from GraphQL and converse them into types and TypeScript. And we can use them in our pages. And this gives us this type safety. And the nice thing about it is we can nest those. We can attach fragments with more fragments. And this is how we start. The way we start is from the query from the page and then it gets the fragments and it goes down to the component level. And for me that's still magic. It's very magical to go to the back end, test the change, and the mobile app complains that this field doesn't exist anymore or this is null, but you expected not to be null. And this connects the whole app.

Another cool trick we use is called routes. I haven't seen this in React Native Apps, so I think it might be very useful for everybody. So what we have is we have this file where we just explore this routes list of, okay, we basically say our screens are routes. So, for example, we have a log in profile route because in our app on every screen you can go to pretty much any other screen. You can just say, okay, this is the description where this thing would go. And we have those hooks to navigate between the different screens. And you can say, okay, I have a route, go back, log in screen, profile screen. And I can use this in a button.

5. React Native Button and Component Structure

Short description:

I have a button that navigates to a product with ID5. We have a core button component with built-in functionality. Our components are used in multiple screens and organized in a directory structure. We have common components, such as text and buttons, with built-in functionality. We also have layout components, including flex row, flex column, and helpers like flex expand and grid. We have utility, styling, and domain components, with deep nesting and a focus on atomic design. Lastly, we have utility functions for various purposes.

I can say I have a button and it navigates to the product with ID5. And this is a very common thing. So what we do is we have built into our core button component. And our core button component just has this.

Well, the next step I'm going to talk about is the components. Those are basically things that are used in more than two screens. And more than one screen, actually. So we use the same component as directory where the root folder shows all the public stuff. The private stuff is all nested. Some components even have, like, 45 levels of components. We keep the graphQL here, the mutation, the index, is where we export. And we have pretty common components. We have our own version of text, so we have consistent text sizing. We have this spacing structure. The other thing we have is, again, the usual buttons. And with us, buttons are not only style, but buttons are also functionality. So we can say, okay, button can link to a page. If the function, which is clicked on, press returns a promise, the button doesn't allow you to tap it again. We also have built-in confirmation, require login, and also it's built-in with GraphQL. So the button can execute a mutation and handle the mutation results. Also, we have packages for buttons. We have a button which is just text, a button which is an icon, a solid, and an outline button.

For layouts, we have extracted out the built-in flex system in Apollo in React Native because we basically got tired of writing the same style over and over again. We have this flex row and flex column and a couple of helpers like flex expand, which expands the flex to the call screen, a grid, which is those dots, and a text, which is basically a hack to have texts float properly with React Native. And as I mentioned, we have utility, styling, and domain, so we actually have also domain components. Like this is the homepage, and if we see the post item, it has a bold button. And this bold button uses the button component, but also the post item uses the bold button and the button, so we have this deep nesting of utility components and domain components. It's kind of like an atomic design, just kind of, with our case, we just say, OK, we have the generic components, and then we have the domain components, which are related to a domain entity. Usually, differences, one have fragments, the other don't. And the final thing I wanted to share is the utilities.

6. Utilities and Styling in React Native

Short description:

I want to tell about some of the utilities we have in our system, focusing on styling. We added a helper for margin and padding, which proved to be very useful. Another feature we implemented was support for dark mode using React Native Dynamic. We have built-in support for dark mode and have a core set of components, as well as domain components that utilize GraphQL. Overall, we have isolated our dependencies and used a directory of construction approach.

I want to tell about some of the utilities we have in our system, and they just live in utilities, in hooks, and in styles. We split it into three folders, because for engineers we have found out it's good to have a dedicated place for things like hooks, and we know that the files there are very special. I want to focus on styling.

One problem which we were writing a lot of styling for was margins and padding. So what we did was we added this helper which we use in our core component, which is, we have those properties for margin and padding. So here is something that on the web, we use the flex-gap property, but this is not something we can implement with React Native. And because of this, we just have this styling helper where we have margin, bottom, padding, and all the associations. And every component can have this spacing prop, so we can add every spacing to those components, and this was very useful.

The other thing which was part of the new feature set was having support for dark mode, which is a cool feature. So we use this package called React Native Dynamic, and we created a wrapper around it where you can use this dynamic style sheet, and depending on the color, you decide what color you are using. And we have a couple of helpers and style themes like, for example, use color background. And we have this color map, which is the dynamic value. So on text with this color, the subtile text is with this color, and every color in our app is defined to this color and has to go to React Native Dynamic. So we actually have built-in support for dark mode. And this is basically how the whole application combines. Like, we built on the foundations, which are the utilities. And we have a lot more smarter utilities. They are a lot more internal helpers. But the one I showed you, I think, are the most memorable and most useful, and I haven't seen a lot of those used in other applications so far. And then on top of them, we build this core set of components, which is we have this core set, which is things like buttons, text, infinite scroll, stuff that they don't care about the domain logic. And then we have the domain component, which is like post button, post button, post item, post thumbnail, which are basically things with fragments, things that take stuff from GraphQL. And then this, the whole thing got combined into the pages, which are wrapped with this help or create page. So to recap that, if you want to take some takeaways from my talk is, yeah, GraphQL is awesome. It helps a really nice to design a system which uses the GraphQL everywhere. From screens, create screen is something which I'm surprised I haven't seen many people use a pattern like that or the screen scalper. And for components, notice how we have isolated a lot of our dependencies. We use directory of construction and we have this concept of domain component. So, yeah, thank you very much. And that's all from me.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

TechLead Conference 2023TechLead Conference 2023
35 min
A Framework for Managing Technical Debt
Let’s face it: technical debt is inevitable and rewriting your code every 6 months is not an option. Refactoring is a complex topic that doesn't have a one-size-fits-all solution. Frontend applications are particularly sensitive because of frequent requirements and user flows changes. New abstractions, updated patterns and cleaning up those old functions - it all sounds great on paper, but it often fails in practice: todos accumulate, tickets end up rotting in the backlog and legacy code crops up in every corner of your codebase. So a process of continuous refactoring is the only weapon you have against tech debt.In the past three years, I’ve been exploring different strategies and processes for refactoring code. In this talk I will describe the key components of a framework for tackling refactoring and I will share some of the learnings accumulated along the way. Hopefully, this will help you in your quest of improving the code quality of your codebases.

React Summit 2023React Summit 2023
24 min
Debugging JS
As developers, we spend much of our time debugging apps - often code we didn't even write. Sadly, few developers have ever been taught how to approach debugging - it's something most of us learn through painful experience.  The good news is you _can_ learn how to debug effectively, and there's several key techniques and tools you can use for debugging JS and React apps.
React Advanced Conference 2022React Advanced Conference 2022
22 min
Monolith to Micro-Frontends
Top Content
Many companies worldwide are considering adopting Micro-Frontends to improve business agility and scale, however, there are many unknowns when it comes to what the migration path looks like in practice. In this talk, I will discuss the steps required to successfully migrate a monolithic React Application into a more modular decoupled frontend architecture.
React Advanced Conference 2023React Advanced Conference 2023
22 min
Power Fixing React Performance Woes
Next.js and other wrapping React frameworks provide great power in building larger applications. But with great power comes great performance responsibility - and if you don’t pay attention, it’s easy to add multiple seconds of loading penalty on all of your pages. Eek! Let’s walk through a case study of how a few hours of performance debugging improved both load and parse times for the Centered app by several hundred percent each. We’ll learn not just why those performance problems happen, but how to diagnose and fix them. Hooray, performance! ⚡️
React Summit 2023React Summit 2023
24 min
Video Editing in the Browser
Video editing is a booming market with influencers being all the rage with Reels, TikTok, Youtube. Did you know that browsers now have all the APIs to do video editing in the browser? In this talk I'm going to give you a primer on how video encoding works and how to make it work within the browser. Spoiler, it's not trivial!

Workshops on related topic

React Summit 2022React Summit 2022
117 min
Detox 101: How to write stable end-to-end tests for your React Native application
Top Content
WorkshopFree
Compared to unit testing, end-to-end testing aims to interact with your application just like a real user. And as we all know it can be pretty challenging. Especially when we talk about Mobile applications.
Tests rely on many conditions and are considered to be slow and flaky. On the other hand - end-to-end tests can give the greatest confidence that your app is working. And if done right - can become an amazing tool for boosting developer velocity.
Detox is a gray-box end-to-end testing framework for mobile apps. Developed by Wix to solve the problem of slowness and flakiness and used by React Native itself as its E2E testing tool.
Join me on this workshop to learn how to make your mobile end-to-end tests with Detox rock.
Prerequisites- iOS/Android: MacOS Catalina or newer- Android only: Linux- Install before the workshop
React Advanced Conference 2022React Advanced Conference 2022
81 min
Introducing FlashList: Let's build a performant React Native list all together
Top Content
WorkshopFree
In this workshop you’ll learn why we created FlashList at Shopify and how you can use it in your code today. We will show you how to take a list that is not performant in FlatList and make it performant using FlashList with minimum effort. We will use tools like Flipper, our own benchmarking code, and teach you how the FlashList API can cover more complex use cases and still keep a top-notch performance.You will know:- Quick presentation about what FlashList, why we built, etc.- Migrating from FlatList to FlashList- Teaching how to write a performant list- Utilizing the tools provided by FlashList library (mainly the useBenchmark hook)- Using the Flipper plugins (flame graph, our lists profiler, UI & JS FPS profiler, etc.)- Optimizing performance of FlashList by using more advanced props like `getType`- 5-6 sample tasks where we’ll uncover and fix issues together- Q&A with Shopify team
React Summit Remote Edition 2021React Summit Remote Edition 2021
60 min
How to Build an Interactive “Wheel of Fortune” Animation with React Native
Top Content
Workshop
- Intro - Cleo & our mission- What we want to build, how it fits into our product & purpose, run through designs- Getting started with environment set up & “hello world”- Intro to React Native Animation- Step 1: Spinning the wheel on a button press- Step 2: Dragging the wheel to give it velocity- Step 3: Adding friction to the wheel to slow it down- Step 4 (stretch): Adding haptics for an immersive feel
React Summit Remote Edition 2021React Summit Remote Edition 2021
87 min
Building a Shopify App with React & Node
Top Content
WorkshopFree
Shopify merchants have a diverse set of needs, and developers have a unique opportunity to meet those needs building apps. Building an app can be tough work but Shopify has created a set of tools and resources to help you build out a seamless app experience as quickly as possible. Get hands on experience building an embedded Shopify app using the Shopify App CLI, Polaris and Shopify App Bridge.We’ll show you how to create an app that accesses information from a development store and can run in your local environment.
JSNation 2022JSNation 2022
41 min
Build a chat room with Appwrite and React
WorkshopFree
API's/Backends are difficult and we need websockets. You will be using VS Code as your editor, Parcel.js, Chakra-ui, React, React Icons, and Appwrite. By the end of this workshop, you will have the knowledge to build a real-time app using Appwrite and zero API development. Follow along and you'll have an awesome chat app to show off!
GraphQL Galaxy 2021GraphQL Galaxy 2021
164 min
Hard GraphQL Problems at Shopify
WorkshopFree
At Shopify scale, we solve some pretty hard problems. In this workshop, five different speakers will outline some of the challenges we’ve faced, and how we’ve overcome them.

Table of contents:
1 - The infamous "N+1" problem: Jonathan Baker - Let's talk about what it is, why it is a problem, and how Shopify handles it at scale across several GraphQL APIs.
2 - Contextualizing GraphQL APIs: Alex Ackerman - How and why we decided to use directives. I’ll share what directives are, which directives are available out of the box, and how to create custom directives.
3 - Faster GraphQL queries for mobile clients: Theo Ben Hassen - As your mobile app grows, so will your GraphQL queries. In this talk, I will go over diverse strategies to make your queries faster and more effective.
4 - Building tomorrow’s product today: Greg MacWilliam - How Shopify adopts future features in today’s code.
5 - Managing large APIs effectively: Rebecca Friedman - We have thousands of developers at Shopify. Let’s take a look at how we’re ensuring the quality and consistency of our GraphQL APIs with so many contributors.