Zero to $10 Million with React Native + Next.js - Fernando Rojo - (Next.js Conf 2021)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
My name is Fernando Rojo and I'm the co-founder  and CTO at BeatGig we're a marketplace for booking   artists you can think of it like Airbnb  for live music. Today I'm going to talk   about using React Native with Next.js my goal with  this talk is to convince you that React Native   is the best way to build a UI even if you're only  making a website one year ago we started building   our product from scratch and I decided to use  React Native with Next.js to build the front end   in the time since we have shipped over 100  screens all of the code lives in a single monorepo   our product works on web iOS and  Android with full feature parity   this is all with one person building and designing  the front end as a result we have grown from zero   to over 10 million in sales in under one year  thanks to our cross-platform stack we can iterate   rapidly and ship features daily our number  one priority is reducing the time from idea   to deployment and React Native is our greatest  instrument in doing so combine it with Next.js   and you can deliver an amazing user experience  on web. Now React Native with Next.js   is a relatively new stack so I faced a few  issues along the way my plan with this talk   is to break down each issue and show you how we  solve them we'll look at navigation animations,  responsive design systems, platform specific  features, monorepo support, and more let's jump in   the biggest difference in structure between  a React Native app and a Next.js website is   navigation so let's see how it works  to the left I have the BeatGig website   and on the right the iPhone app let's compare  what happens when I open some artist profiles   okay here we have it open on the website I'll do  the same on the app looks basically the exact same   I'll go back and let's do one more I'll open B.o.B  on the website and now on the app so let's compare   what happened on the website we have @bob here in  the URL on the iPhone app there's obviously no URL   and the only real difference is that on the  iPhone app I can swipe back here and I got   the stack transition in so I'll go back and I'll  go back here on the website too the key thing to   take away here is the design is mostly shared and  the logic is fully shared between platforms but we   still match the user's expectations based on the  platform they're using. Let's see how we do it   this part is really cool we're going to use the  same screens across Next.js and React Native our   first step is to create a shared artist screen  component I'll expect every file in the screens   folder to be shared across platform next I'll  create a Next.js page at pages/artist/slug   and I'll import that same artist screen component  all we have to do is default export it and our   artist screen is now working on Next.js for  the search screen I'll create a shared search   screen component import it in pages search  and default export it if you use Next Router   this should look really familiar we now have  our React Native pages rendering on Next.js   the missing piece is how do we use the same  screens in the React Native iPhone and Android app   here we're looking at app.tsx React Native  uses this file as a single entry point rather   than use file system routing we're going  to create a stack from React Navigation   here I've imported create native stack  navigator which does that for us I'm also   going to import the same screen components  which we just used for our Next.js pages   now I have an empty navigator and the only missing  piece is to add our screens and there we have it   we now have our two screens  uniquely identified by the name prop   search and artist and the component  prop tells us which component to render   this is what the final code looks like the only  difference is that I add a NavigationContainer   which is the provider for React Navigation. Let's recap where we just shared some code   first I import the shared artist screen component  in app.tsx for React Native I then pass artist   screen to React navigation's stack via the  component prop to use the same screen in Next.js   all I have to do is import it in pages/artist/slug  and default export it and there we go you now know   how to share screens between a React Native  app and a Next.js website the question is   how do we move between screens if you're on the  search page and you want to open an artist page   how do you do it can you just use the Next Link  or Next.js's router push or is there another way?  Let's take a look. I made a library called  expo-next-react-navigation which lets you   share all your navigation code between Next.js  and React Native this is what it looks like   it's very similar to next it has a link component  and a useRouting hook you can create a custom link   like this to open an artist and if you need  more customization you can use the web prop   if the route name from native doesn't match  your path on web unlike Next Router it uses   params instead of query which does the same thing  reading in our params is also very similar to Next   this is what it looks like on Next  and with expo-next-react-navigation   instead of query we just use params and  everything else is basically the same in   the future I want to have an API like this where  it's fully shared between Next and React Native but there are still some things in the way  and if you want to help you can check out   this issue I opened on the repository called  "The future API" and I would love to hear your   thoughts and get your contributions. Next let's  talk animations coming from a web background   I always loved using simple things like CSS  transitions and more advanced libraries like   React Spring and Framer Motion in the past year  there have been some incredible innovations   for performant animations in React Native  with the introduction of Reanimated 2.   That said before I even started using React Native  Web something I felt I was missing in React Native   when it came to performant animations was a simple  API in 2019 this feature request was opened on the   Framer Motion repo for React Native support it was  one of those issues that got a ton of attention   a lot of upvotes but was outside of the scope  of what Framer Motion was focused on which was   just the web this inspired me to write an RFC  in October of 2020 for a simple cross-platform   animation library for React Native and React  Native Web I wanted to borrow a lot of the cool   features from Framer Motion like mount animations  and automatic transitions and I ultimately decided   to build my own library called Moti and I  launched it on twitter about eight months ago   in the time since Moti has gotten almost 2,000  stars and has gained quite a bit in popularity. This is what it looks like to use Moti you  get a Moti view and a Moti text component   you can use the from prop for mount  animations and anything you pass to   animate will automatically transition which makes  it really easy to animate based on React state   you can also get full control of your animations  using the transition prop like Framer Motion one   of my favorite features of Moti is the mount  and unmount animations. Under the hood Moti   uses Framer Motion's animate presence to bring  this feature to React Native for the first time   in fact Matt Perry from Framer Motion recommends  Moti as the native compatible alternative if you   want to animate based on hovered or pressed states  with Moti it's as simple as passing a function   to your animate prop you can interpolate between  hovered and press states and the results will   automatically animate without triggering any  re-renders that means we get cross-platform   animations that run at 60 frames per second one  of my favorite design patterns is animating a   component when someone hovers or presses it notice  what happens when I hover over the see more link   see that the background turns yellow and  when I hover over an artist they scale up getting this kind of feature parody between  a website and an iPhone app would previously   be really challenging but with React  Native, React Native Web, and Moti   this parity comes out of the box. To the  right we have the BeatGig iPhone app,   let's see what happens when I press on the see  more button the background also turns yellow just   like the website and when I press in on the artist  as I scroll they also scale up the exact same way with Moti you can also do more advanced  interaction based animations such as animating   the children of a pressable component if you open  the BeatGig website and hover over products in the   header you get this nice drop down each item has a  background transition and an icon that animates in   or out this is actually built with Framer Motion  and React state because I hadn't launched Moti   interactions yet but once I shipped this on the  website I wanted to try to remake it with Moti   here we have the exact same component from  BeatGig's website built with Moti what I   find interesting is this is a web only  component and yet implementing it with   Moti which is a React Native library was a  lot simpler than doing so with web libraries   I think this is a common side effect of building  with React Native and React Native Web. Rather   than focus on platform-based implementation  you think strictly about the UI and as a result   you come up with APIs that are a lot simpler than  what probably existed the code for this drop down   is open source and I'll link to it at the end of  the talk Next.js is a first class citizen of Moti   add Moti to your next transpile modules  add a single polyfill and you're good   to go let's look at one final animation  example animating based on scroll position   on the right we have the BeatGig iPhone app to  the left the mobile website notice that the header   fades in when I scroll down the animation code  here is shared 100% cross platform and there's   actually no special library in play here this is  using the vanilla animated API from React Native   for simple things like scroll animations  this API is quite easy to use and can get   you great performance. Next let's talk theming  and responsive design back in 2017 I was running   an ecommerce sneaker brand called Patos I wanted  to make some custom edits to my shopify website   so I started learning CSS and javascript and  it didn't take long to fall in love with both   soon enough I considered myself a web developer  I was using CSS all the time so when I started   styling and React Native I had some mixed feelings  to start let's compare what it looks like to style   in CSS and React Native next I'll discuss the  pros and cons of React Native's styling system   and finally I'll show you what we do here we  have a component class name written in CSS   and at the bottom we have the equivalent in React  Native React native has a built-in stylesheet API   rather than use classname we'll pass this to the  component directly using the style prop. If I want   to use multiple styles I just pass an array in  this case I'm forwarding props.style the order   of the styles is determined by their order in  the array which is a lot more predictable than   CSS I can also do conditional styles in this case  I'm only applying props.style if props.isEnabled   is true finally if you want to add dynamic styles  you can do that by putting them in line like this   for a deeper understanding of styling and  React Native I recommend checking out the docs   but hopefully that gives you a good  overview of the differences with CSS   next let's look at the pros and cons first the  pros there are no global styles in React Native   at first I viewed this as an annoying limitation  but it's actually crucial if you want to know   the styles applying to a component you just  look at the style prop it's dead simple and   there's no risk of accidentally setting a global  style that has side effects on other components   there are no nested styles like there are in  CSS. All styles are scoped to a single component   and the logic is handled on the JavaScript side  making each component incredibly predictable React   Native also doesn't have pseudo elements if you  want to track a component's focus state you use   the onFocus prop instead of the CSS selector this  is a lot safer as it maintains your components   as a function of their state and you can come  back to it months later and know exactly what's   going on. Finally in React Native there  are no issues with import order of styles   with CSS you can cause many bugs simply by the  position in which you import a file on the other   hand in React Native if you want to know the  order of styles that are applying to a component   you just look at the style prop there are no  cascading styles no nested styles no global styles   everything is scoped to a single component  which means your component based design system   is scalable. For a long time I thought I loved  CSS and part of me still does but once I started   styling with React Native it was pretty hard  to go back the level of predictability and   simplicity lets you move so quickly and keeps you  from getting bogged down by little CSS bugs and   platform-based issues one interesting thing is the  stylesheet API from React Native Web is actually a   highly optimized CSS in JS solution if you want  to see how companies like Twitter use this on   their website I highly recommend this talk by the  creator of React Native Web , Nicholas Gallagher Okay now the cons of styling in React  Native React native doesn't have CSS grid   this isn't the biggest issue in the world but it  would just be nice to have it next React Native   doesn't have the concept of media queries so  responsive design can be a bit challenging   you have to actually use JavaScript to  track screen dimensions in render in fact   React Native Web actually recommends not using  media queries instead they take the position   that you should render different component trees  altogether based on screen size or view container   size so what's the verdict I've spent a few  years building with both CSS and React Native   and ultimately the low level styling API provided  by React Native and React Native Web is better   than that of CSS the level of predictability and  scalability in a component-based design system   is too hard to beat now there are some  missing pieces and in these cases I think   it's up to us to build libraries to add in  features like theming and responsive design   let's take a look at how we solve these things  for BeatGig. In 2019 this feature request for   React Native support was opened on the Chakra UI  repo I thought this was pretty exciting because I   wanted a library like chakra for React Native  and React Native Web with unstyled components   I ultimately decided to build my own library  called Drips. Dripsy is a set of responsive   un-styled UI primitives for React Native and React  Native Web based on a theme this is what it looks   like to use Dripsy it's heavily inspired by Theme  UI from React on the left we have our theme and   on the right we can style a component using the  sx prop so I'll try adding a background color   and here it pulls values straight from my theme if  I want to make a value responsive such as padding   all I need to do is pass an array here  it'll use the third scale on mobile devices   and 0 on any screen bigger than that we now  have a way to use theming and responsive   design across platforms creating a consistent  user experience no matter where your users are   next let's talk platform specific features every  now and then I come across a feature from web that   doesn't yet exist in React Native. Two good  examples are anchor tags for scrolling down a   page and URL query parameters let's take a look at  how we use these features in a cross-platform app   and then I'll show you how you can make  your own something I love about HTML  is how easy it is to scroll from one part  of the page to another using an anchor tag   the issue is React Native doesn't have anchor  tags so to get around it I built my own library   called Anchor. Anchor lets you scroll to any  arbitrary component inside of any scroll view   it works cross-platform with the exact same API  I found this to be especially useful when a user   submits a form and I want to scroll down to the  errors. To the left we have the BeatGig website   and on the right the iPhone app let's see what  happens if I submit the form with missing fields   notice that it turns red and scrolls  to the correct field let's do the same   thing on the iPhone app and the same thing  happens so I'll enter my offer amount here   and I'll do the same thing on the app and I'll  hit submit again and now it takes me down to   the date so this time I'll set a future date say  December 2nd and I'll set one on the app as well alright so I'll submit one more time and  it takes me down to performance length   so I'll fill this in do it on both and now we  have the app submitting on both for offers to   Loud Luxury. Here we were able to use anchors  to nudge users along the way and make the form   experience much more enjoyable even when there  are errors next let's take a look at using URL   query parameters across platforms something  I find really cool is using query parameters   as our React state so I made a hook called  useParam which lets us do just that what's cool   is this hook actually works cross platform on web  it uses next router to get the query parameters   and on native it uses normal React state here I  have a name and a set name returned by useParam   which works just like use state the first step  is to set the actual name of the query parameter   which in this case is just name and  that is pulling from the types up here   when I call set name it should set it in the  query parameters and use that as my state   so I'll try that here and there we go now  it's rendering this name it's in the query   parameters and if I refresh I maintain my exact  same state let's try adding a clear name function I'll just set the name to null and then I'll add a  button all right so I'll go ahead and click clear   name and now it's back to null it clears that out  of the query parameters and there's nothing here   now let's look at a more complicated example  using age which is a number. The reason this   is more complicated is because age is a number and  query parameters are always strings so here I have   TypeScript complaining the reason is because I  need to parse the value in from the URL string   so in this case I'll use the parse function which  gives you the value from the query parameters and   it expects you to return the type you want  so in this case I'm going to return a number   based on the query parameter I have okay but  why is this still upset well what happens on the   initial render if you don't set a value you need  to set initial similar to use state from React   and there we have it we now have an age query  parameter which is a number gets parsed in   from the URL and also lets you set an initial  value if it's undefined on the first render   to recap parse works similar to a JSON parse but  you can do it by query parameter now if I wanted   to have a custom value in here let's say it was  number or hello in this case the age type is going   to recognize that parse returns number or hello  but I'll just clear that out and now age is always   going to be a number this is especially useful  if in parse you want to restrict users to only   a specific set of types for example you might want  it to be a number that's only one, two, or three   and you can handle that inside of parse and that  is it this is probably the most useful hook I have   and it's so simple it works just like React state  across platforms but on web it lets you manage it   all through your query parameters next let's  look at writing our own platform specific code   to run different code based on the platform  you're using import platform from React  Native using platform.os you can distinguish  between your platform and run different code   typically you'll want to provide a fallback for  other platforms alternatively you can import   different files altogether based on the platform  using a dot platform extension on a file name in   this case index.web.ts will be imported on web and  index.ts will be imported on all other platforms   and you can do this for as many platforms  as you want in general I actually recommend   against writing platform-specific code directly  in your app in fact in the Moti docs I wrote that   using Platform.OS is an anti-pattern if you find  yourself needing to write platform specific code   chances are you've found a good idea for an open  source library platform inconsistencies should be   handled by third-party libraries so that apps can  always build with a single unified API next let's   take a look at the monorepo structure for React  Native Next.js app the best way to structure a   React Native nexus app is with the monorepo here I  have a packages folder and an applications folder   inside of applications I have my two separate  entry points "next" is just my Next.js app as   you'd expect and "expo" is the React Native app  that will run on iOS and Android. Expo provides a   set of libraries and services that makes building  and deploying with React Native super easy while   it isn't a perfect comparison in many ways Expo  is to React Native what Next.js is to React it   makes shipping your product into production a way  better experience I highly recommend using expo , for the React Native side I find this to be pretty  uncontroversial I won't spend too long on this   instead at the end of the talk I'll link to an  example monorepo which you can use as your starter   With React Native we have an instrument to turn  ideas into component based products quickly   combine it with Next.js and we can leverage the  best features the web has to offer but there's   still work to be done and if you want to take part  in building the cross-platform stack of the future   I encourage you to follow and reach out to me on  twitter @fernandotherojo I hope you enjoyed this   talk and I can't wait to see what ideas you have  to keep pushing this stack forward. Thank you.
Info
Channel: Vercel
Views: 4,544
Rating: undefined out of 5
Keywords:
Id: 0lnbdRweJtA
Channel Id: undefined
Length: 24min 43sec (1483 seconds)
Published: Wed Oct 27 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.