🌍 ReactJS · subject
ReactJS React Performance Optimization Syllabus
The React Performance Optimization syllabus for ReactJS in full: 3 chapters and 9 topics, every one listed below, plus 50 React Performance Optimization flashcards with answers.
React Performance Optimization syllabus: all 3 chapters
Expand any chapter to see its topics and sub-topics.
-
Code Splitting
3 topics- What is Code Splitting?
- Implementing Code Splitting
- Lazy Loading Components
-
Memoization
3 topics- Using React.memo
- Using useMemo
- Using useCallback
-
Performance Monitoring
3 topics- Using React Profiler
- Analyzing Performance Metrics
- Optimizing Slow Components
ReactJS React Performance Optimization flashcards — 50 questions with answers
What is code splitting in React?
Code splitting is the technique of breaking a large application bundle into smaller chunks that are loaded on demand, rather than shipping one giant JavaScript file. It reduces the initial bundle size and improves initial load time.
What problem does code splitting solve?
It solves the problem of large initial bundles that delay the first meaningful paint. Instead of forcing users to download all code upfront, only the code needed for the current view is loaded, deferring the rest until needed.
Which bundlers support code splitting out of the box for React apps?
Modern bundlers such as Webpack, Rollup, Vite, and Parcel support code splitting automatically, primarily through the dynamic import() syntax which creates separate chunks.
What JavaScript syntax is the foundation of code splitting?
The dynamic import() expression, e.g. import('./MyModule'), which returns a Promise and tells the bundler to create a separate chunk that is fetched at runtime.
What is the difference between static and dynamic imports regarding code splitting?
A static import (import X from './x') is bundled into the main chunk at build time. A dynamic import (import('./x')) returns a Promise and creates a separate chunk loaded at runtime, enabling code splitting.
What is route-based code splitting?
Route-based code splitting splits the bundle along route boundaries, loading the code for a page only when the user navigates to that route. It is one of the most effective splitting strategies because users rarely visit every route.
How do you implement code splitting for a React component using built-in APIs?
Use React.lazy with a dynamic import: const MyComp = React.lazy(() => import('./MyComp')). React.lazy returns a component that loads the chunk when first rendered.
What must wrap a React.lazy component and why?
A <Suspense> boundary must wrap it, because the lazily loaded component may not be ready immediately. Suspense provides a fallback UI (e.g. a spinner) to show while the chunk is loading.
Write a minimal example of code splitting with React.lazy and Suspense.
const Chart = React.lazy(() => import('./Chart')); function App() { return ( <Suspense fallback={<Spinner />}> <Chart /> </Suspense> ); }
What is the required prop on the Suspense component?
The fallback prop, which specifies the React element to render while the lazily loaded children are still loading (e.g. fallback={<Loading />}).
What is lazy loading of components?
Lazy loading defers the loading of a component's code until it is actually needed (e.g. rendered for the first time), rather than including it in the initial bundle. In React this is done with React.lazy plus Suspense.
What are the constraints on modules used with React.lazy?
React.lazy only works with default exports. The dynamic import must resolve to a module whose default export is a React component. Named exports must be re-exported as default or wrapped.
How can you lazy load a named export with React.lazy?
Re-export it as default in an intermediate module, e.g. React.lazy(() => import('./MyComp').then(m => ({ default: m.NamedComp }))), because React.lazy expects a module with a default export.
What is an error boundary's role with lazy loading?
If a lazily loaded chunk fails to load (e.g. network error), the promise rejects. An Error Boundary placed above the Suspense catches this failure and can show a fallback error UI, preventing a crash.
What is React.memo?
React.memo is a higher-order component that memoizes a functional component, skipping re-render when its props are shallowly equal to the previous props. It optimizes components that render the same output for the same props.
What kind of components benefit most from React.memo?
Pure functional components that render often with the same props, are relatively expensive to render, and receive props that change infrequently. Cheap or always-changing components gain little or nothing.
By default, how does React.memo compare props?
It performs a shallow comparison of each prop between the previous and next render. If all props are referentially equal (===), it skips the re-render.
How do you customize React.memo's comparison logic?
Pass a second argument, an arePropsEqual(prevProps, nextProps) function that returns true to skip the re-render and false to re-render. This overrides the default shallow comparison.
Why can passing an inline object or arrow function as a prop defeat React.memo?
Inline objects/functions create a new reference on every render, so the shallow prop comparison always sees them as changed. React.memo then re-renders anyway. Use useMemo/useCallback to stabilize references.
What is useMemo?
useMemo is a Hook that memoizes the result of an expensive computation, recomputing it only when one of its dependencies changes: const value = useMemo(() => compute(a, b), [a, b]).
Show the other 30 React Performance Optimization flashcards
What is the signature of useMemo?
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]); the first argument is a factory function, the second is the dependency array.
When should you use useMemo?
When a computation is genuinely expensive, or when you need a stable reference for a value passed to a memoized child (React.memo) or used in another Hook's dependency array.
Does useMemo run its factory during rendering or after?
useMemo runs the factory during rendering. Therefore the factory must be pure and must not cause side effects; side effects belong in useEffect.
What is the difference between useMemo and useEffect?
useMemo computes and returns a memoized value synchronously during render for performance. useEffect runs side effects after render (e.g. data fetching, subscriptions) and returns nothing meant for rendering.
What is useCallback?
useCallback is a Hook that returns a memoized version of a callback function that only changes when its dependencies change: const fn = useCallback(() => doSomething(a), [a]).
State the equivalence between useCallback and useMemo.
useCallback(fn, deps) is equivalent to useMemo(() => fn, deps). useCallback memoizes the function itself, whereas useMemo memoizes the result of calling a function.
Why is useCallback important when passing handlers to memoized children?
Without it, a new function reference is created each render, breaking React.memo's shallow comparison and forcing the child to re-render. useCallback preserves the reference so the memoized child can skip re-rendering.
What is the dependency array's role in useCallback and useMemo?
It lists the reactive values the memoized function/value depends on. React re-creates the memoized result only when a listed dependency changes (by Object.is comparison); an empty array [] means it never changes after mount.
What happens if you omit the dependency array in useMemo or useCallback?
Omitting the array causes the value/function to be recomputed on every render, defeating the memoization entirely and providing no performance benefit.
Compare React.memo, useMemo, and useCallback in one sentence each.
React.memo memoizes a whole component to skip re-renders; useMemo memoizes a computed value; useCallback memoizes a function reference. All three rely on referential stability of dependencies/props.
What is the React Profiler?
The React Profiler is a tool (available in React DevTools and as a <Profiler> component) that measures how often components render and the cost of rendering, helping identify performance bottlenecks.
What are the two ways to use the React Profiler?
1) The Profiler tab in React DevTools, which records commits interactively. 2) The programmatic <Profiler> component from React, which fires an onRender callback with timing data.
What arguments does the Profiler component's onRender callback receive?
onRender(id, phase, actualDuration, baseDuration, startTime, commitTime): id of the tree, phase ('mount' or 'update'), actualDuration (time to render this commit), baseDuration (estimated time without memoization), and timing timestamps.
In the Profiler onRender callback, what does actualDuration measure?
actualDuration is the time spent rendering the Profiler subtree for the current commit. It should decrease over subsequent commits if memoization is working, since only changed components re-render.
In the Profiler, what does baseDuration represent?
baseDuration is the estimated time to render the entire subtree without any memoization, i.e. the worst-case cost. Comparing it to actualDuration shows how much memoization saves.
What is a 'commit' in the React Profiler?
A commit is a single point where React applied changes to the DOM. The Profiler records each commit separately, letting you inspect which components rendered and how long each took during that commit.
What is a flame graph in the React Profiler?
A flame graph is a visualization where each bar represents a component in the render tree; the bar's width/color indicates how long that component took to render in the selected commit, making expensive components easy to spot.
What is the 'ranked' chart in the React Profiler?
The ranked chart lists the components that rendered in a commit ordered from most to least time spent, so you can immediately identify the single most expensive components.
What is the difference between the 'mount' and 'update' phase in the Profiler?
'mount' is the initial render when the component tree is first added to the DOM; 'update' is a subsequent re-render caused by state, props, or context changes. The phase argument in onRender distinguishes them.
Why should performance profiling be done in production/optimized builds?
Development builds include extra checks, warnings, and no minification, making them significantly slower. Profiling a production build gives realistic timings; React provides a special profiling build for accurate DevTools measurement.
What are Core Web Vitals?
Core Web Vitals are Google's key user-centric performance metrics: Largest Contentful Paint (LCP, loading), Interaction to Next Paint (INP, responsiveness, replacing FID), and Cumulative Layout Shift (CLS, visual stability).
What does Largest Contentful Paint (LCP) measure and what is a good threshold?
LCP measures the time until the largest visible content element renders. A good LCP is $\leq 2.5$ seconds; needs improvement is $2.5$ to $4.0$ s; poor is $> 4.0$ s.
What does Cumulative Layout Shift (CLS) measure and what is a good value?
CLS measures unexpected layout movement of visible content during page load (visual stability). A good CLS score is $\leq 0.1$; poor is $> 0.25$. It is a unitless score.
What does Time to First Byte (TTFB) measure?
TTFB measures the time from the request until the first byte of the response is received from the server. It captures server responsiveness and network latency and is a foundation for other loading metrics.
What is First Contentful Paint (FCP)?
FCP measures the time from navigation until the browser renders the first piece of DOM content (text, image, etc.). A good FCP is $\leq 1.8$ seconds.
How do you compute a component's average render time from Profiler data over $n$ commits?
Sum the actualDuration values and divide by the number of commits: $$\bar{t} = \frac{1}{n}\sum_{i=1}^{n} t_i$$ where $t_i$ is the actualDuration of commit $i$.
What is a common cause of a slow component that re-renders too often?
Unstable references (new objects, arrays, or functions created inline each render) passed as props or context values, causing children to re-render. Fix with useMemo, useCallback, and React.memo.
Name three strategies to optimize a slow-rendering list.
1) Windowing/virtualization (render only visible rows, e.g. react-window). 2) Provide stable, unique key props. 3) Memoize row components with React.memo to avoid re-rendering unchanged rows.
What is windowing (virtualization) and when is it useful?
Windowing renders only the subset of list items currently visible in the viewport (plus a small buffer) instead of the whole list. It is essential for long lists/tables, drastically reducing DOM nodes and render time.
What is the general workflow to optimize a slow React component?
1) Measure with the Profiler to find the bottleneck. 2) Identify the cause (frequent re-renders, expensive computation, large DOM). 3) Apply the fix (memoization, virtualization, code splitting, state colocation). 4) Re-profile to confirm the improvement.
ReactJS React Performance Optimization FAQ
What is in the ReactJS React Performance Optimization syllabus?
ReactJS React Performance Optimization is split into 3 chapters: Code Splitting, Memoization and Performance Monitoring. Together they contain 9 topics.
How many chapters are in ReactJS React Performance Optimization?
3 chapters, containing 9 topics. The largest chapter is Code Splitting, with 3 topics.
Are there flashcards for ReactJS React Performance Optimization?
Yes — a 50-card React Performance Optimization deck, printed in full in the flashcards section of this page and available in the Examius app with spaced repetition. The free plan covers one exam of your choice, including its flashcards; Examius Pro, a one-time purchase, unlocks every other exam and deck.