🎵 React Summit '21 Notes
Peter Sun /
- Internationalizing React?
- Remote Rendering With Web Workers
- Building Better Websites With Remix
- Let's Build React Query in 150 Lines of Code!
- Scaling React Development with Nx
- Doing the Least Amount of Work Possible: An Intro to Runtime Performance
- Lessons Learnt from Building Interactive React Applications
- Building Accessible React Components
- React on the Blockchain
- Platform powered: Build a Frontend Platform to Scale as fast as You do?
- Test Kitchen: A Recipe for Good Tests
- How Core Web Vitals Will Affect Google Ranking in 2021
- XState: The Visual Future of State Management
- Lessons To Outlive React
- Graphic = fn(state)
- Build a UI that learns: Intelligent Prefetching with React and TensorFlow.js
- We Don't Know How react State Hooks Work
- Inside Fiber: An Overview Of React's Reconciliation Algorithm
- Building the Right Product and Building It Right: A Glimpse into Extreme Programming and Atomic Design React Without Javascript?
- Stories and Strategies from Converting to TypeScript
🪙 Credit goes to all speakers at React Summit '21
Internationalizing React#
Definitions
- i18n (internaltionalization) — Process of architecting your app so l10n works
- l10n (localization) — Making the content and experience suitable for a given locale
Requirements
- Formatting the date correctly based on locale (see the date formatting libraries).
- Allowing bidirectionally of content layout since there are some languages that read from right to left vs the common left to right (see the RTL formatting libraries).
- Text should be translated for different languages.
Locale Overview
There are 5 parts to localization: language
, script
, country
, variant
and extension
. The most common used is just language
and country
codes as denoted in es-ES (left value is the language and the right value is the country) for spanish in spain. The data type used for accessing translation stting are standardized to ensure this look up heavy process is fast.
const TranslationMap = { "en-ES" : { SomeLabel: "Translated Label Text" } }
References
- Internationalization — depends on locale and country code
- Date Formatting — depends on locale and country code
- RTL (right to left) — depends on if we want too render LTR or RTL direction
Remote Rendering With Web Workers#
Introduction
Shopify built this to run external code in a safe a secure way (i.e making the web worker a sandbox).
💡 This can be extended to be run on the server instead to define components.
Core Concepts
- Javascript sandbox
- Securely execute code in a background thread
- Communicate to the main thread by sending messages (see RPC section).
- As a web worker on web and as a headless JS engine on iOS/Android
- RPC — Remote procedure calls for communication between the main thread and helper (web worker / headless JS engine)
- Proxy layer — A way of allowing the host to call functions in the JS sandbox and vice versa
Libraries
Building Better Websites With Remix#
Why Remix?
- Remix fully server side rendered react pages, this means it seems like a single page application but only sends the minimum required javascript and css files for running what is rendered.
- Styles are programmatically removed when their respective routes are not rendered.
- JSX is compiled to HTML via react.hydrate and only that is sent to the browser.
Why not Remix?
- There direct competitor is NextJS and are more battle tested
- Remix is still in early access and is not free OSS
References
Let's Build React Query in 150 Lines of Code!#
Requirements
- It needs to fetch, cache and update the data.
- Data should be able to come from anywhere (i.e client) as long as it returns a promise.
- It should provide cached data until it is updated.
- It should be only triggered once even if used in multiple components.
System Design
- We need to keep track of these different values (i.e using state) in an API request. These allows us to cache queries and prevent duplicate inflight queries:
isFetching
data
error
status
lastUpdated
queryHash
— The query parameters used and their corresponding dataqueryKey
— The query parameters usedpromise
— A pointer to hold onto the resolving promise (i.e in flight API request)subscribers
— Who to notify when fetched data has changed?
- Client should be defined by users (and abstracted) in case you would like to use a custom built API client.
- Query observer to update any subscribers, refetching logic with stale time, clearing cache (i.e garbage collection)
💡 You can force rerenders via const [,rerender] = React.useReducer (i=>,o)
Scaling React Development with Nx#
Core Concepts
Nx is a library to help monorepo management, specifically:
- Dependency graph (on how the react components are imported)
- New project creation (based on best practices)
- Dependency constraints (in case some pages should not access certain internal libraries or only access shared libraries)
💡 Note that Nx seems to be opinionated about best practices which might conform to how things are done for you (requires prototyping to see if the project is suitable).
References
Doing the Least Amount of Work Possible: An Intro to Runtime Performance#
Core Concepts
Runtime performance starts when the page is fully interactive and the javascript has been loaded into the browser (i.e blocking the main thread). This are some runtime performance issues:
- Computationally expensive tasks
- Animations and graphical updates
- Reflow/Repaint and layout
- Parsing
- Memory Leaks
A runtime performance drop is apparent since the website freezes up, drops frames or has input delay. There are some prescriptive things to improve runtime performance (do not over optimize):
- Use regular for loops (i.e scale properly overtime)
- Instead of searching large arrays, use lookup tables
- Avoid creating new objects
- Turn off animation (perceived performance)
- Avoid reflow/relayouts
- Caching
- Sneaky tricks (i.e set object index to undefined instead of using the delete keyword)
How To
- Profile runtime performance
- Go to the developer console in Google Chrome.
- Go to the performance tab and click record.
- Perform the action you want to measure.
- Anything with the red indicator is blocking the main thread.
- Right clicking and selecting performance indicator will bring up the CPU usage chart of the app.
- Profile specific sections of code (runtime performance related):
- Add the
performance.mark
to the start and end of the relevant code to measure. - Add
performance.measure
to compare between the start and end markers. - Begin profiling runtime performance (see 1). There will be a new
timings
field with the relevant markers to view how long each step is taking.
- Add the
- Profile memory performance
- Go to the developer console in Google Chrome.
- Go to the memory tab and click record.
- Perform the action you want to measure.
- The objects stored in memory will be visible (and their corresponding variable naming) and how they evolved (vs before the snapshot).
Lessons Learnt from Building Interactive React Applications#
Core Concepts
Animation should always be used to provide visual cues to the user hinting what to expect. These are some tips when designing animations for web / application interactions:
- Subtly fading in text after loading (without a loading indicator feels more native like the page is loading but this does not work for load times > 500ms).
- Transform position of content from where it should be coming from (clicking back should move the current page should to the right).
- Be sure to take into considerations accessibility concerns in reduce motion.
Libraries
- Framer motion (hides abstraction when components are initially placed in the DOM)
Building Accessible React Components#
Introduction
The main guideline used to benchmark accessibility is WCAG. There are 3 grades to achieve A
, AA
, AAA
(minimum grade to be considered accessible is A
)
Main Principles
- Perceivable — Content can be viewed by sight impaired users.
- Operable — Keyboard / mouse, text read via screen reader, etc
- Understandable — Know which input fields are required, etc
- Robust — Isn't buggy.
Form Specific Tips
These are some important element properties when designing forms to be accessible are :
required
— If this input is required.aria-required
— If this input is required when there is no HTML5 support.aria-labeledby
— If this input has specific instructions and links to another DOM element with text (i.e another DOM element labels this input element).aria-describedby
— Similar toaria-labeledby
, but will overridearia-labeledby
. It is useful to tag errors with this component.aria-invalid
– Used in conjunction witharia-describedby
, if it an error.aria-disabled
- Used instead ofdisabled
; Disabled removes elements from the accessibility tree.
Generic Concerns
- Do not remove focus outlines, making it transparent helps with high contrast edge cases.
- Make sure items are focusable where needed (try tab-ing in each page).
- Dialogs are tricky and using libraries like
react-a11y-dialog
is suggested instead of building from scratch. content-visibility
should be used to hide elements out of the viewport.- Adding commas are great in
alt
text for when the screen reader should pause. - Navigating / creating a new tab should be explicitly mentioned in links under the
alt
text. - Media queries are a great way of capturing if the reduce motion option is toggled.
References
- jsx-a11y
- axe-core/react
- pa11y
- storybook-addon-a11y
- WAVE Browser Extensions
- Web AIM Color Contrast Checker
React on the Blockchain#
References
web3
is an interface to the blockchaintruffle
is used to build smart contractssolidity-coverage
is used for lintingopenzeppelin-solidity
is used for the math behind hashing on the merkle tree
Platform powered: Build a Frontend Platform to Scale as fast as You do?#
Introduction
Usually tools and processes are only effective in one order go magnitude of scale in a company, different approaches help in the various levels of scale. In Lyft, they migrated from monolith to micro services which lead to:
- Long lived services required maintenance
- Platform was fragmenting
- Infrastructure updates were hard to apply (support is required for all versions released)
Core Concepts
Building the application as a tiered service, this allows seperation of concerns:
- Top layer; App — Apps frontend which most developer work on to ship features.
- Mid Layer; Libraries — The helper methods most used in the top layer.
- Low Layer; Infrastructure — Configurations to build the Javascript bundle
The lower two levels are managed with a core team to empower the top layer (where all product engineers work on). The most problems come in the middle layer in terms of managing and structuring libraries (to prevent bloat and duplication).
Lyft Specific Solution
- Building on top of NextJS (since it comes out of the box with best practices to follow) which solves the lowest level of the stack.
- Standardizing libraries which help business logic development via:
- Library helpers for frontend functions (essentially services to build a react context for passing information through the application).
- Express middleware for serverside functions.
- JSCodeShift to migrate breaking changes like exported naming from libraries (no longer run into breaking changes).
- Versioned migrations to allow better tracking of what migrations should be run (since they are stateful).
- Tying both the platform and library versions (this joins the two layers into one).
Test Kitchen: A Recipe for Good Tests#
Core Concepts
- Test should inspire confidence that the core functionality does not break.
- Tests should be automated (so developers do not have to run it manually and we can run it all the time). It is important to run on the branch before merging and on the main branch after merging.
- Tests should be fast:
- Run tests in parallel.
- Do not wait/sleep in tests unless necessary.
- Tests should be behavioral and structure intensive and be based on the consumer perspective where possible.
- Tests should be deterministic (same input and output), isolated (independent from other tests) and composable(runnable without side effects and race condition).
- Tests should be specific and one per test case.
- Tests should be short.
- Test should have a good description.
- Tests should be expressive (visual regression instead of validating snapshot for color changes).
- Test should be writable.
How Core Web Vitals Will Affect Google Ranking in 2021#
Core Concepts
It is important to increase performance; since a decrease of 100ms on latency increases sales by 1%. The best way to measure this performance is through the end user perceived experience via Core Web Vitals
:
- Measuring Loading —
LCP
; Largest Contentful Paint, This is when the largest item has been loaded on to the screen (Good < 2.5s > Meh < 4s > Poor). - Measuring Interactivity —
FID
; First Input Delay, This is when the first input has been interacted with and when the browser processes the event (Good < 100ms?> Meh < 300ms > Poor). - Measuring visual stability —
CLS
; Cumulative Layout Shift, This is when the content moves on the page?(Good < 0.1 > Meh < 0.25 > Poor).
NextJS Specific Tips
- Prerender content via Static generation or server sider rendering.
- Optimize images:
- Use image and with to prevent layout shift.
- Lazy load images based on viewport.
- Use modern image types (WebP).
- Use source sets to load correct image quality per device.
- Optimize fonts:
- Use a variable font.
- Preload your font file.
- Use
font-display: optional
to prevent layout shifts.
References
XState: The Visual Future of State Management#
Introduction
State and events are the best way to application state (think about redux) but are not easy to visualize. XState tries to take learnings from Redux but makes it state first and allows it to be easily visualized, test generation, analytics and autogeneration. It allows you to catch DOM events and updating the state accordingly.
Library Specific Functions
createModel
— Allows you to store data (also know as context)createMachine
— Creates the state machineuseSelector
— Pulls data from the machine
References
Lessons To Outlive React#
They can be grouped into core
, interface
, productionize
and humanize
concepts. These are the lessons in detail:
- Reconciler + Scheduler Pattern
- To make a program regenerate every time, add caching and structural sharing of previous files.
- This means each build system has two parts, a scheduler which ?orchestrates what and when work needs to be done and the rebuilder which hashes and then decide whether to build or extract from the cache.
- Minimal API Surface Area (similar to YAGNI)
- Remove as much complexity as you add , it's much easeier to recover from an explicit and repetitive API.
- Use design patterns instead of increasing the framework.
- API Design is Language Design
- Name something with better intent and assumption they will become part of language.
- Optimize for Change
- It should be easy to read and write (memorable, guessable, unambiguous and readable).
- Easy to change as new requirements come in (production pivots).
- Enable local Reasoning by having all context within the same file so users do not have to grok global context.
- Test the Public API (write test for what is exposed to the user).
- Devtools is not optional.
- React Codemods are great to auto migrate code.
- Error codes — Allows better understanding and standardization of possible errors.
- Readable lint errors in console — So users know what they are doing wrong
- Fixtures — Be able to toggle on different feature flags for different combination of use cases
- Hold the line — Do not allow your important stats to move in the wrong direction (test coverage, type coverage, bundle sizes, perf metrics, etc)
- Community is Important, listen to feedback (they are the network effect).
Scaling Component Across Multiple Frameworks#
Core Concepts
The best way to create a standardized component would be to create a DOM element at the low level via CustomElements
(see mozilla docs on custom elements) and only uses native functionality. This element will be usable with React Angular, etc.
Libraries
Graphic = fn(state)#
Core Concepts
User experience is always a function of state (we always show things based on some state). This applies to icons as well which means we should be abstracting icons as React components since SVGs can be rendered dynamically with props (change color and size).
Build a UI that learns: Intelligent Prefetching with React and TensorFlow.js#
Core Concepts
In a large single page app, the best way to reduce bundle size is to defer the loading of each screen until navigation happens (via React.lazy). To optimize the flow, sometimes we want to prefetch routes to reduce the loading time. In this use case, data can be collected to identify user's full navigation pattern (per session); With Deep Learning, it allows the system to predict the sequence or next page the user will be navigating to. The best way to share this deep learning model is through Tensorflow's model object; Analysis is done in the backend and prediction are run in the client.
References
We Don't Know How React State Hooks Work#
💡 Setting state in an async function, each call to set state will cause a re-render (eager loading). If it is within one function context, all calls to set states will be implemented before the UI is updated (lazy loading).
Inside Fiber: An Overview Of React's Reconciliation Algorithm#
Introduction
To match 60fps, a new frame is displayed every 16ms
. This means if the rendering and reconciliation takes > 16ms
, there would be a dropped framed with causes a choppy or janky UI (this is extremely important for Javascript since it is a single threaded language). React Fiber does a simulation of being multi threaded by scheduling and prioritizating work. We can interactiwith it via React's Concurrent which is experimental. For example, useDeferred
hook schedules the work with a different priority. This means the reconcilation can:
- Pause work and resume it later (and not block the thread).
- Assign different priorities to different types of work.
- Reuse previously computed work, or throw it away if no longer needed.
Definitions
- Fiber — A Javascript object that contains information about a component, it's input, and it's output. This is the smallest unit in React (each element is represented as a Fiber).
- Fiber Trees — A in-memory version of the DOM React uses to compute what components should be updated. There is a
current
andwork-in-progress
tree to compute the current and future states. Another way to think about these two trees are like the master branch vs your personal branch.When the work is completed, you push to master without hindering it's state and when it's convenient to the master branch (in this case main thread should be available). - Two phase algorithm — On the first pass, it does reconciliation (pause-able/continue-able) and the second pass it does commit (uninterruptible).
Building the Right Product and Building It Right: A Glimpse into Extreme Programming and Atomic Design#
Core Concepts
- Communication — Heavily communicate so everyone is on the same page
- Simplicity — We want to build the smallest MVP to test the ideas.
- Feedback — We want to get feedback ASAP to provide more insight for the next iteration of the work
- Courage — Throw things away if users don't use it
- Respect — Respect all opinions and create a safe space for it
Job Descriptions
- Product Mangers — Get buy in from the company and ensure features are broken down in a sustainable product roadmap.
- Designers — Evaluate the product design and extract the feedback from the users.
- Engineers — Evaluate feasibility and implement the work.
Stories and Strategies from Converting to TypeScript#
Core Concepts
- Take note of hidden costs (user interviews) before proposals, etc.
- Hype train is really useful for pushing people to adopt new.
- Advertise it by helping individuals understand the problem and the solution.
- Knowledge Sharing is important via
Internal Presentation
/Brown Bags
/Code Pairing
(does not scale but useful). - Spreading consensus with two helpers:
- Area Experts — People who know the technology on the best practices and how to bring it into the company (2 per project to bounce off ideas)
- Cheerleaders — People are excited to try things out to be beta testers and help as the network effect (1 per affected team)
- Create a style guide document where possible and have a FAQs.
- Automate wherever possible.
- Never convert and change behavior.
- Celebrate, so people remember the work!
Typescript Specific Workflow
- Convert few files (minimal disruption without sudden change).
- Integrations should be built up beforehand for the incremental change.
- Ensure these configurations are turned on to prioritize ease of adoption:
allowJS/checkJS
:off
— No need to disrupt engineer with messages for legacy code.noImplicitAny
:off
— Too time consuming & difficult in a JS/TS codebase.strictNullchecks
:on
— Useful and not expensive.
- Have dedicated PRs for converting things to typescript to allow bite size work for various engineers to try the migration. The PR description should explain any new syntax for others.
- Monitor how the Typescript percentage changes overtime.
- Optimize for comfort so everyone feels comfortable with the changes.
- Used TypeStat (custom helper) to programmatically help creating types, etc.
- Any casts are fine to get things to migrate to Typescript.