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 />