React Native at
The NetCircle
Tim Wang @timwangdev
Frontend Developer
The Status
- 15 modules (auth, comments, profile, inbox...)
- 30+ screens
- 15000+ lines of TypeScript code
- Build with react-native, redux, realm
- Replaced previous native modules with JavaScript implementation
The Good Parts
-
Code Sharing
- Bustiness Logic: 100%
- UI Code: Up to 95%
- Different UI decisions between Android and iOS
- Wrapper for native modules in JavaScript side
- Native Code: Only use for infrastructure, and connection with system call or native modules.
- Still exploring shareable module with the website but current web tech stack is quite old
Platform Specific Code Example
import { Platform, ActionSheetIOS } from 'react-native';
import BottomSheetAndroid from 'react-native-bottom-sheet';
import trans from '@/core/i18n';
const showSheet = Platform.OS === 'android'
? BottomSheetAndroid.showBottomSheetWithOptions
: ActionSheetIOS.showActionSheetWithOptions;
const options: Array<string> = [
trans('B_VIEW_PROFILE'),
trans('B_SEND_NO_THANKS'),
trans('B_HIDE'),
trans('B_DELETE'),
trans('B_CANCEL'),
];
// class ... {
private onButtonPress = () => {
showSheet({ options }, callbacks);
}
-
React
- React is still great declarative library for building user interface
-
Native Integration
- Almost* everything can be bridged to native code, which provides easy binding with platform APIs and native libraries.
-
Performance
- Works great in most cases
- Common optimization for React app still valid
- Bottleneck usually comes from "the bridge"
OSS Community (JavaScript/React)
Source: The State of the Octoverse 2017 (https://octoverse.github.com/)
-
Open Source Community
- Large community
- facebook/react-native has the second most contributors on Github in 2017
- Cross platform libraries
-
Tooling
-
yarn, jest, babel, typescript
-
- Third-party support (Microsoft, CircleCI, Bitrise, etc.)
- Commercial-friendly licenses (MIT)
- Contribute back to upstream
- Large community
The "🤔" Parts
JavaScript
-
TypeScript
- helps us a lot with build time type checking
- Require additional step to set up
- Types for third-party module may not being
accurate - Use with self-restriction (`any`)
- DevTools (source-map) may experience line number shift issues
// Example.ts
let foo = '12'; // Type inference as string
foo = 42; // Error: Type '42' is not assignable to type 'string'.
let bar: any = '12';
bar = 42; // No error
-
The "npm" issue
-
Don't mix `yarn` with `npm`
-
Use `yarn.lock`
-
Lock version for package contains native code
- Explicit dependencies version (babel@7)
-
-
Use Linter
- Avoid using bad language features (`==`)
- Avoid common mistakes
- Provide unified code style across the team members
-
Patch/Fork Broken Modules
-
patch-package
- Self-maintained type definitions
- Make pull requests when appropriate
-
-
Use Latest Language Feature
- async/await, Object spread operator, Set/Map
- TC39 proposals
-
React Navigation
- No official navigation solution from RN
- Community-driven project
- Implemented in JavaScript
- More flexibility
- No standard native widgets
- Moving fast but brings lots of breaking changes
- We maintained a fork to custom some usage for v1, but we'd like to follow the official release for v2.
The Pit 🙁
-
Native Development Experience
- One repository contains three environments code (And submodule structure didn't work so well)
- Dose not following native package conventions (CocoaPods/Maven)
- Lack of documentation
- Tools always make assumption of project structure
-
Android Build
- Outdated tooling version (gradle 3.5.+)
- Outdated JavaScriptCore version
- Yoga minimal bugs (inconsistent with iOS)
-
Developer Requirement
- Objective-C/Java knowledge is required to debug native errors
- Xcode/Android Studio experience
- Code sign and release process
-
Mix RN and Native Screens
- Integration with exist apps (brown field)
- Sync navigation state between native and JavaScript realm is very hard
- Poor react native bridge performance
-
Debug experience
- Remote debugger in Chrome is unstable, it's runs on browser environment and V8 engine
- Use Safari inspect tools
- Sourcemap is not reliable (TypeScript transformer issue)
- console.log is still the best way
-
Upgrading React Native
- Native APIs has no guarantee of backward compatibility
- Patching core framework is hard
- Upgrade every two minor release (eg. 0.54.* => 0.56.*)
-
App Size
- Framework take the size about 12Mb, although JS bundle may only have 2Mb minified
-
Additional Memory Usage
The Future* and Beyond
-
"Rearchitecture" React Native
- The bridge
- Threading modal
- Async rendering (Likely land in React 17)
-
Collaboration with the Project
- Actively track issues/ new fix/ releases
- Communication with core team
-
Make Native Packages
- Isolating developer environment
- Better upgrade path
Universal UI Development
-
JavaScript Environment
- JS engine is cross-platform fast and lightweight
- Universal modules (No browser/node required)
- Single thread and event loop modal is great for client-side applications
- TypeScript gives the typing check feature but still keeps the flexibility (deno)
-
React Primitive
- Virtual DOM isolating pure render logic
- react-reconciler
- React Native async rendering modal
- Use <View/>, <Text/>, <Image/> everywhere
- Use "Native" module to access the platform
- Windows/ macOS/ Web/ SVG/ VR/ AR and more
References
-
React Native at Airbnb - Gabriel Peal - https://medium.com/airbnb-engineering/react-native-at-airbnb-f95aa460be1c
-
State of React Native 2018 - Sophie Alpert - https://facebook.github.io/react-native/blog/2018/06/14/state-of-react-native-2018
-
Sneak Peek: Beyond React 16 - Sophie Alpert, Dan Abramov - https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-react-16.html
-
Should we use React Native? - Charlie Cheever -
https://blog.expo.io/should-we-use-react-native-1465d8b607ac
-
Bridging React Native Back to its Roots - Vincent Riemer - https://www.youtube.com/watch?v=aOWIJ4Mgb2k