Our Practices of Building a React Web App

ZHUORAN LI

GitHub: @lzhuor

🎵 Clarinet, 🏀 Basketball, 🎿 Ski

🤯 What's happening?

    The "library"

    Small Scope

Evan You on Vue.js: Seeking the Balance in Framework Design | JSConf.Asia 2019

 

    "Warning"

  • Opinionated
  • Mostly for SPA
  • Different thoughts are more than welcome!

Delivery of Design

😭 Sketch

Components

Core

Frontend

workspace

Monorepo

Check out once, develop all!

Components

  • Shared components, usable across scenes, modals and layouts that are behaving in the same way
  • Generic, in the way that different components could potentially use them with specific implementations

Core

  • Contains all the Redux & Saga modules shared across the platform
    • composing data of micro-services or BFF*
    • model the resources of your domain
    • API interactions
  • Only needed if you really know why you need it, usually for complex domain models
    • client-side Cryptowallet is a good usecase

Core

Redux & Sagas

Core

API Client

Frontend

  • The actual web app implements business logics

👨‍💻‍

workspace

Monorepo

{
  "test": "cross-env yarn wsrun test:build --fast-exit && yarn wsrun test"
}
{
  "test:components": "yarn workspace silver-components test"
}

Styling

  • Inline props
  • Flexibility
    • Generic HTML tags 
    • Wrap existing components
    • Global styles
  • Theme

styled-components

const Container = styled.div`
  background: ${props => props.bgColor};
`
const Container = styled(BaseContainer)`
  background: red;
`

Use defined name of color instead of hex code

Layouts

<PublicLayout />

<SilverLayout />

  • Authentication
const ShareFormContainer = styled.div`
  margin: 3.2rem 0;
  display: flex;
  align-items: center;

  ${media.maxWidth.mobile`
    margin-bottom: 0;
    flex-direction: column;
  `};
`
  • Consistent
    • breakpoints of Grid system
    • breakpoints of Media Query (in CSS)
    • <MediaContext /> API (in JSX)

Responsiveness

  const { mobile } = useContext(MediaContext)

Responsiveness

Bundle Analysis

  "scripts": {
    "analyze": "cross-env-shell ANALYZE=true NODE_ENV=production webpack-cli --config webpack.config.prod.js"
  }

Code Split

  • By route (URL)
  • By frequency
  • By feature
  • By region / language

💪 Alternative (SPA): React.lazy & <Suspense />
https://reactjs.org/docs/code-splitting.html

Code Split

import Loadable from 'react-loadable'
import LoadableLoading from 'scenes/Common/LoadableLoading'

const Declaration = Loadable({
  loader: () =>
    import(
      /* webpackChunkName: "declarations" */ 'scenes/Onboarding/Declaration'
    ),
  loading: LoadableLoading
})

Code Split

Survey.sg.a9dn1kdf7.js

Survey.us.f6alekd5m.js

Tooltips

Declare once, use anywhere!

Layout Component

Modals

Layout Component

Modals

HOC

Declare once, use anywhere!

Error Tracking

  • React Render
    • <ErrorBoundary/>
  • Anything else in JavaScript
    • selectors
    • reducers
    • helpers, services, providers
    • and more...
  • Redux & Redux-Saga
    • use middleware
  • User
  • HTML Events & Redux Actions
  • URL, Device, IP, Browser
  • Stack Trace
  • API Interactions
  • App Version
  • etc.

Sentry

Staging

Sample

Sentry

Staging

Sample

Sentry

Staging

Sample

Internationalisation

  • Translation
    • en.json
    • zh.json
  • Formatting
    • Money, Date, Number, Plurals etc.

Internationalisation

  • String
  • HTML (not encouraged)
  • React Component
  • Templating

 plugin

Coding Styles

FP with Ramda.js

  • Immutable
  • Expressive
  • Purity, code is easy to test
  • Conceptually compatible with HOC, Functional Component, Redux

Migrating to Hooks

  • Lifecycle
  • Local State
  • Context consumer
  • react-redux connector
  • Custom HOCs

Note: One challenge you may encounter with useEffect Hooks

react-redux v7.1 Hooks

Migrating to Hooks

useAction

Migrating to Hooks

useNotifications

Redux-Form

<Context />

Forms

20+

QA