JavaScript and React course Β· Module 8: Advanced React Patterns

Performance Profiling

11 min read
In this lesson7

Our cosmic journey through React is nearing its end, but before we set off for further explorations, we need to make sure our spaceship is running at maximum capacity. In this module, we will focus on profiling the performance of React applications - that is, identifying and analyzing "bottlenecks" in our code.

What is performance profiling?

Performance profiling is the process of identifying places in an application that consume the most resources (CPU time, memory) and may lead to slow user interface behavior. It is like diagnosing the engines of a spaceship to check which parts are not running efficiently and can be optimized.

In the context of React applications, profiling allows you to:

  • Identify components that render too often
  • Locate long-running operations
  • Understand rendering patterns
  • Detect unnecessary state updates
  • Point out areas requiring optimization

React profiling tools

1. React DevTools Profiler

React DevTools is a browser extension that allows analyzing the performance of React applications. It includes a "Profiler" tab, which is the simplest and most powerful tool for profiling React applications.

How to use React DevTools Profiler:

  1. Installing React DevTools

  2. Starting profiling:

    • Open browser developer tools
    • Go to the "Profiler" tab in React DevTools
    • Click the record button (red circle)
    • Perform actions in the application you want to profile
    • Stop recording
  3. Analyzing results:

    • Flame Chart - shows the hierarchy of rendered components and their rendering time
    • Ranked Chart - sorts components by rendering time
    • Component Chart - shows which components were re-rendered in each update

Interpreting colors in the Profiler:

  • Gray - the component did not render during the update
  • Yellow/Orange/Red - the component rendered, and the color indicates how long it took (the more red, the longer)
  • Black - the component was the cause of the update (e.g., by changing state)

2. Chrome Performance Panel

Chrome DevTools includes a Performance panel that allows for more general page performance profiling:

  1. Starting profiling:

    • Open DevTools in Chrome (F12)
    • Go to the "Performance" tab
    • Click the record button
    • Perform actions in the application
    • Stop recording
  2. Analyze results:

    • Main - shows activity on the main thread (where most JS work happens)
    • Frames - shows frames per second (FPS)
    • Network - shows network activity
    • Memory - shows memory usage

This panel is particularly useful for identifying:

  • Long-running scripts blocking the main thread
  • Excessive DOM operations
  • Rendering performance issues

3. Built-in React profiling API

React provides a built-in API for profiling in development mode:

1// Import the Profiler component
2import { Profiler } from 'react';
3
4// Callback function called after rendering
5function onRenderCallback(
6  id, // identifier of the profiled component tree
7  phase, // "mount" (first render) or "update" (re-render)
8  actualDuration, // time spent rendering
9  baseDuration, // estimated render time of the entire subtree without optimizations
10  startTime, // when React started rendering
11  commitTime, // when React finished rendering
12  interactions // set of "interactions" tracked for this render
13) {
14  console.log({
15    id,
16    phase,
17    actualDuration,
18    baseDuration,
19    startTime,
20    commitTime
21  });
22}
23
24// Using the Profiler component in the application
25function App() {
26  return (
27    <Profiler id="MissionControl" onRender={onRenderCallback}>
28      <MissionControl />
29    </Profiler>
30  );
31}

You can nest Profiler components to profile different parts of the application:

1function Dashboard() {
2  return (
3    <Profiler id="Dashboard" onRender={onRenderCallback}>
4      <h1>Mission Control Panel</h1>
5
6      <Profiler id="Navigation" onRender={onRenderCallback}>
7        <Navigation />
8      </Profiler>
9
10      <Profiler id="Stats" onRender={onRenderCallback}>
11        <MissionStats />
12      </Profiler>
13
14      <Profiler id="Crew" onRender={onRenderCallback}>
15        <CrewStatus />
16      </Profiler>
17    </Profiler>
18  );
19}

This method of profiling is particularly useful when:

  • You want to collect performance data in a test environment
  • You have specific components you want to monitor
  • You want to automate performance data collection

Common performance issues and how to profile them

1. Components rendering too frequently

Problem: Components re-render even when their data hasn't changed.

How to profile:

  • Use React DevTools Profiler to see which components render too often
  • Check if parent components are causing unnecessary child renders

Example of the problem:

1function ParentComponent() {
2  const [count, setCount] = useState(0);
3
4  // This function is created anew on every render
5  const handleClick = () => {
6    console.log('Button clicked');
7  };
8
9  return (
10    <div>
11      <button onClick={() => setCount(count + 1)}>
12        Increase counter: {count}
13      </button>
14
15      {/* ChildComponent will re-render on every count change,
16          even though handleClick has the same functionality */}
17      <ChildComponent onClick={handleClick} />
18    </div>
19  );
20}

Solution:

1function ParentComponent() {
2  const [count, setCount] = useState(0);
3
4  // Function memoization prevents creating a new reference on every render
5  const handleClick = useCallback(() => {
6    console.log('Button clicked');
7  }, []);
8
9  return (
10    <div>
11      <button onClick={() => setCount(count + 1)}>
12        Increase counter: {count}
13      </button>
14
15      {/* ChildComponent wrapped in React.memo won't re-render
16          when its props don't change */}
17      <MemoizedChildComponent onClick={handleClick} />
18    </div>
19  );
20}
21
22const MemoizedChildComponent = React.memo(ChildComponent);

2. Heavy computations during rendering

Problem: Performing complex calculations during rendering causes UI delays.

How to profile:

  • Observe in React DevTools Profiler which components have the longest rendering time
  • Use Chrome Performance Panel to see long JavaScript tasks

Example of the problem:

1function DataAnalytics({ data }) {
2  // Heavy computations performed on every render
3  const processedData = processLargeDataset(data);
4  const statistics = calculateStatistics(processedData);
5
6  return (
7    <div>
8      <h2>Mission Data Analysis</h2>
9      <DataVisualisation stats={statistics} />
10    </div>
11  );
12}

Solution:

1function DataAnalytics({ data }) {
2  // Memoizing heavy computations - they only run when data changes
3  const processedData = useMemo(() => {
4    return processLargeDataset(data);
5  }, [data]);
6
7  const statistics = useMemo(() => {
8    return calculateStatistics(processedData);
9  }, [processedData]);
10
11  return (
12    <div>
13      <h2>Mission Data Analysis</h2>
14      <DataVisualisation stats={statistics} />
15    </div>
16  );
17}

3. Excessive state updates

Problem: Too frequent state updates cause cascading re-renders.

How to profile:

  • In React DevTools Profiler, find components marked in black (update initiators)
  • Observe update patterns - are some components updating in groups?

Example of the problem:

1function SpaceshipSensors() {
2  const [temperature, setTemperature] = useState(0);
3  const [pressure, setPressure] = useState(0);
4  const [oxygen, setOxygen] = useState(0);
5  const [radiation, setRadiation] = useState(0);
6
7  // Fetching sensor data every 100ms
8  useEffect(() => {
9    const interval = setInterval(() => {
10      // Each update causes a separate render
11      setTemperature(getTemperature());
12      setPressure(getPressure());
13      setOxygen(getOxygen());
14      setRadiation(getRadiation());
15    }, 100);
16
17    return () => clearInterval(interval);
18  }, []);
19
20  return (
21    <div>
22      <h2>Sensor Readings</h2>
23      <p>Temperature: {temperature}Β°C</p>
24      <p>Pressure: {pressure} hPa</p>
25      <p>Oxygen level: {oxygen}%</p>
26      <p>Radiation level: {radiation} ΞΌSv/h</p>
27    </div>
28  );
29}

Solution:

1function SpaceshipSensors() {
2  // Storing related data together in a single state object
3  const [sensorData, setSensorData] = useState({
4    temperature: 0,
5    pressure: 0,
6    oxygen: 0,
7    radiation: 0
8  });
9
10  useEffect(() => {
11    const interval = setInterval(() => {
12      // One state update instead of four
13      setSensorData({
14        temperature: getTemperature(),
15        pressure: getPressure(),
16        oxygen: getOxygen(),
17        radiation: getRadiation()
18      });
19    }, 100);
20
21    return () => clearInterval(interval);
22  }, []);
23
24  return (
25    <div>
26      <h2>Sensor Readings</h2>
27      <p>Temperature: {sensorData.temperature}Β°C</p>
28      <p>Pressure: {sensorData.pressure} hPa</p>
29      <p>Oxygen level: {sensorData.oxygen}%</p>
30      <p>Radiation level: {sensorData.radiation} ΞΌSv/h</p>
31    </div>
32  );
33}

4. Large lists and data visualizations

Problem: Rendering long lists or complex visualizations can slow down the interface.

How to profile:

  • Use React DevTools Profiler to identify list components that take a long time to render
  • Check how often individual list items render

Example of using React DevTools to profile list performance:

  1. Start profiling
  2. Scroll the list to see how the application responds
  3. Stop profiling
  4. Check which components have the longest rendering time in the ranked chart

Solution:

  • List virtualization (React Window, React Virtualized)
  • Memoizing list items
  • Pagination instead of displaying all elements at once

Advanced profiling techniques

1. User Timing API

The Browser Performance API allows creating custom time markers:

1function ExpensiveComponent({ data }) {
2  useEffect(() => {
3    // Start measurement
4    performance.mark('expensive-calculation-start');
5
6    // Perform expensive calculations
7    const result = performExpensiveCalculation(data);
8
9    // End measurement
10    performance.mark('expensive-calculation-end');
11
12    // Create measurement between markers
13    performance.measure(
14      'expensive-calculation',
15      'expensive-calculation-start',
16      'expensive-calculation-end'
17    );
18
19    // Log results
20    console.log(performance.getEntriesByName('expensive-calculation'));
21  }, [data]);
22
23  //
24}

These markers will be visible in the Performance panel in Chrome DevTools.

2. Production performance monitoring

For monitoring performance in production, you can use:

  • Web Vitals - a Google library for measuring key performance indicators
  • New Relic, Datadog, Sentry - APM (Application Performance Monitoring) tools
  • Custom solutions using the Performance API and Profiler API

Example of collecting data from React Profiler and sending it to a server:

1function onRenderCallback(id, phase, actualDuration, baseDuration, startTime, commitTime) {
2  // We only collect data from the update phase that takes longer than 10ms
3  if (phase === 'update' && actualDuration > 10) {
4    sendToAnalyticsServer({
5      componentId: id,
6      renderTime: actualDuration,
7      timestamp: Date.now()
8    });
9  }
10}
11
12function App() {
13  return (
14    <Profiler id="App" onRender={onRenderCallback}>
15      <AppContent />
16    </Profiler>
17  );
18}

Case study: Profiling and optimizing a React application

Let's analyze the process of profiling and optimizing the performance of a React application using the example of a space mission control panel:

Step 1: Identifying the problem

Users report that the control panel is slow, especially when displaying telemetry data and the event list.

Step 2: Profiling the application

We use React DevTools Profiler to identify the source of the problem:

  1. We record a session during normal panel use
  2. We analyze the results in the Profiler
  3. We discover that:
    • The TelemetryChart component renders very slowly (>100ms)
    • The EventsList component re-renders every time new telemetry data arrives
    • The calculateTrends function takes a lot of CPU time

Step 3: Optimization

Based on the profiling results, we introduce the following optimizations:

  1. Optimizing TelemetryChart:
1// Before optimization
2function TelemetryChart({ data }) {
3  // Heavy data processing on every render
4  const chartData = processChartData(data);
5
6  return <LineChart data={chartData} />;
7}
8
9// After optimization
10const TelemetryChart = React.memo(function TelemetryChart({ data }) {
11  // Memoized data processing
12  const chartData = useMemo(() => processChartData(data), [data]);
13
14  return <LineChart data={chartData} />;
15});
  1. Optimizing EventsList:
1// Before optimization
2function EventsList({ events }) {
3  return (
4    <div>
5      {events.map(event => (
6        <EventItem key={event.id} event={event} />
7      ))}
8    </div>
9  );
10}
11
12// After optimization
13const EventsList = React.memo(function EventsList({ events }) {
14  return (
15    <div>
16      {events.map(event => (
17        <MemoizedEventItem key={event.id} event={event} />
18      ))}
19    </div>
20  );
21});
22
23const MemoizedEventItem = React.memo(EventItem);
  1. Moving heavy computations to a web worker:
1// Before optimization
2function MissionControlPanel({ telemetryData }) {
3  const trends = calculateTrends(telemetryData);  // Blocks the main thread
4
5  return (
6    <div>
7      <TrendsDisplay trends={trends} />
8      {/* other components */}
9    </div>
10  );
11}
12
13// After optimization
14function MissionControlPanel({ telemetryData }) {
15  const [trends, setTrends] = useState(null);
16
17  useEffect(() => {
18    if (!telemetryData) return;
19
20    // Create a web worker
21    const worker = new Worker('./trendsWorker.js');
22
23    // Listen for response
24    worker.addEventListener('message', (event) => {
25      setTrends(event.data);
26      worker.terminate();
27    });
28
29    // Send data for processing
30    worker.postMessage(telemetryData);
31  }, [telemetryData]);
32
33  return (
34    <div>
35      {trends ? <TrendsDisplay trends={trends} /> : <LoadingSpinner />}
36      {/* other components */}
37    </div>
38  );
39}

Step 4: Verifying optimizations

After introducing optimizations, we profile the application again:

  1. TelemetryChart rendering time dropped from >100ms to ~15ms
  2. The EventsList component no longer renders on telemetry data updates
  3. The main thread is no longer blocked by calculateTrends

Thanks to these optimizations, the user interface runs smoothly, and the control panel responds immediately to user interactions.

Best practices for profiling

  1. Profile in a production-like environment

    • Run the application in production mode (npm run build and serve the built files)
    • Test on devices similar to those used by users
  2. Establish baselines

    • Measure performance before and after optimizations
    • Set specific performance goals (e.g., first render time < 2s)
  3. Profile regularly

    • Include profiling in the application development cycle
    • Monitor performance after introducing major changes
  4. Focus on user perception

    • Prioritize optimizations that have the greatest impact on perceived performance
    • Remember key Web Vitals metrics (LCP, FID, CLS)
  5. Document profiling results

    • Record performance data before and after optimizations
    • Share knowledge and optimization techniques with the team

Summary

Performance profiling is an essential element of creating high-quality React applications. Just as space engineers monitor every aspect of a ship's operation, we should continuously analyze the performance of our applications to ensure users have a smooth and responsive experience.

Key points to remember:

  1. Use the right tools - React DevTools Profiler, Chrome Performance Panel
  2. Identify bottlenecks - find components that render too often or too long
  3. Apply appropriate optimization techniques - memoization, avoiding unnecessary renders, list virtualization
  4. Measure the effectiveness of optimizations - compare performance before and after changes
  5. Optimize in moderation - remember that premature optimization can lead to overly complicated code

With these profiling techniques and tools, you will be able to create performant React applications that provide an excellent experience for users, even in the most complex cosmic control panel interfaces.

Code for this lesson: App.jsx
1import React, { useState, useMemo, useCallback, useEffect, useRef, Profiler } from 'react';
2
3// ============================================
4// REACT PERFORMANCE PROFILING
5// ============================================
6// This example demonstrates optimization techniques
7// and profiling of React components.
8
9// --- Profiling callback ---
10function onRenderCallback(id, phase, actualDuration, baseDuration) {
11  console.log(
12    `[Profiler] ${id} | phase: ${phase} | actual: ${actualDuration.toFixed(2)}ms | base: ${baseDuration.toFixed(2)}ms`
13  );
14}
15
16// --- Simulating a heavy computation ---
17function expensiveCalculation(items) {
18  let result = 0;
19  for (let i = 0; i < items.length; i++) {
20    for (let j = 0; j < 1000; j++) {
21      result += Math.sqrt(items[i].value * j + 1);
22    }
23  }
24  return result.toFixed(2);
25}
26
27// --- Component WITHOUT optimization ---
28function UnoptimizedChild({ label, onClick }) {
29  const renderCount = useRef(0);
30  renderCount.current += 1;
31
32  return (
33    <div style={childStyle}>
34      <span>{label}</span>
35      <span style={renderBadge}>{renderCount.current}x rendered</span>
36      <button onClick={onClick} style={btnStyle}>Click</button>
37    </div>
38  );
39}
40
41// --- Component WITH optimization (React.memo) ---
42const OptimizedChild = React.memo(function OptimizedChild({ label, onClick }) {
43  const renderCount = useRef(0);
44  renderCount.current += 1;
45
46  return (
47    <div style={{ ...childStyle, borderColor: '#4CAF50' }}>
48      <span>{label}</span>
49      <span style={{ ...renderBadge, background: '#4CAF50' }}>{renderCount.current}x rendered</span>
50      <button onClick={onClick} style={{ ...btnStyle, background: '#4CAF50' }}>Click</button>
51    </div>
52  );
53});
54
55// --- List component with virtualization (simplified) ---
56function VirtualizedList({ items, itemHeight = 40, containerHeight = 200 }) {
57  const [scrollTop, setScrollTop] = useState(0);
58  const containerRef = useRef(null);
59
60  const visibleStart = Math.floor(scrollTop / itemHeight);
61  const visibleCount = Math.ceil(containerHeight / itemHeight) + 1;
62  const visibleItems = items.slice(visibleStart, visibleStart + visibleCount);
63
64  return (
65    <div
66      ref={containerRef}
67      onScroll={(e) => setScrollTop(e.target.scrollTop)}
68      style={{
69        height: containerHeight, overflow: 'auto',
70        background: '#0d1b2a', borderRadius: '8px', border: '1px solid #2a3f5f',
71      }}
72    >
73      <div style={{ height: items.length * itemHeight, position: 'relative' }}>
74        {visibleItems.map((item, i) => (
75          <div
76            key={item.id}
77            style={{
78              position: 'absolute', top: (visibleStart + i) * itemHeight,
79              height: itemHeight, width: '100%', padding: '8px 12px',
80              boxSizing: 'border-box', borderBottom: '1px solid #1b2838',
81              color: '#e0e1dd', display: 'flex', alignItems: 'center',
82            }}
83          >
84            {item.name} - value: {item.value}
85          </div>
86        ))}
87      </div>
88    </div>
89  );
90}
91
92// --- Main application ---
93function App() {
94  const [count, setCount] = useState(0);
95  const [filterText, setFilterText] = useState('');
96  const [showOptimized, setShowOptimized] = useState(false);
97
98  // We generate a list of 500 elements
99  const largeList = useMemo(() => {
100    return Array.from({ length: 500 }, (_, i) => ({
101      id: i,
102      name: `Mission #${i + 1}`,
103      value: Math.floor(Math.random() * 1000),
104    }));
105  }, []);
106
107  // Filtering with useMemo - calculations run only when data changes
108  const filteredItems = useMemo(() => {
109    return largeList.filter((item) =>
110      item.name.toLowerCase().includes(filterText.toLowerCase())
111    );
112  }, [largeList, filterText]);
113
114  // Heavy computation with memoization
115  const expensiveResult = useMemo(() => {
116    return expensiveCalculation(filteredItems.slice(0, 50));
117  }, [filteredItems]);
118
119  // Callback WITHOUT memoization (new reference on every render)
120  const handleClickUnoptimized = () => {
121    console.log('Click without memoization');
122  };
123
124  // Callback WITH memoization (stable reference)
125  const handleClickOptimized = useCallback(() => {
126    console.log('Click with useCallback');
127  }, []);
128
129  return (
130    <div style={appStyle}>
131      <h1 style={{ color: '#ffd700', textAlign: 'center', marginBottom: '8px' }}>
132        React Performance Profiling
133      </h1>
134      <p style={{ textAlign: 'center', color: '#aaa', marginBottom: '20px' }}>
135        Open the browser console to see the Profiler logs
136      </p>
137
138      {/* Section 1: React.memo + useCallback */}
139      <Profiler id="MemoDemo" onRender={onRenderCallback}>
140        <div style={sectionStyle}>
141          <h2 style={headingStyle}>React.memo + useCallback</h2>
142          <p style={{ color: '#aaa', marginBottom: '12px' }}>
143            Click "+1" and observe which component re-renders.
144          </p>
145          <div style={{ textAlign: 'center', marginBottom: '16px' }}>
146            <span style={{ fontSize: '24px', marginRight: '12px' }}>Counter: {count}</span>
147            <button onClick={() => setCount((c) => c + 1)} style={btnAccent}>+1</button>
148          </div>
149
150          <div style={{ display: 'flex', gap: '12px', flexWrap: 'wrap' }}>
151            <div style={{ flex: 1, minWidth: '220px' }}>
152              <h3 style={{ color: '#ff6b6b' }}>Without optimization</h3>
153              <UnoptimizedChild
154                label="Component A"
155                onClick={handleClickUnoptimized}
156              />
157            </div>
158            <div style={{ flex: 1, minWidth: '220px' }}>
159              <h3 style={{ color: '#4CAF50' }}>With React.memo + useCallback</h3>
160              <OptimizedChild
161                label="Component B"
162                onClick={handleClickOptimized}
163              />
164            </div>
165          </div>
166        </div>
167      </Profiler>
168
169      {/* Section 2: useMemo on heavy computations */}
170      <Profiler id="UseMemoDemo" onRender={onRenderCallback}>
171        <div style={sectionStyle}>
172          <h2 style={headingStyle}>useMemo - heavy computations</h2>
173          <p style={{ color: '#aaa', marginBottom: '12px' }}>
174            Filtering and calculations are memoized - changing the filter recalculates the result.
175          </p>
176          <input
177            value={filterText}
178            onChange={(e) => setFilterText(e.target.value)}
179            placeholder="Filter missions..."
180            style={inputStyle}
181          />
182          <p style={{ margin: '8px 0', color: '#ffd700' }}>
183            Calculation result: {expensiveResult} | Found: {filteredItems.length} missions
184          </p>
185        </div>
186      </Profiler>
187
188      {/* Section 3: List virtualization */}
189      <Profiler id="VirtualizedListDemo" onRender={onRenderCallback}>
190        <div style={sectionStyle}>
191          <h2 style={headingStyle}>List virtualization (500 elements)</h2>
192          <p style={{ color: '#aaa', marginBottom: '12px' }}>
193            Only visible elements are rendered - scroll the list.
194          </p>
195          <label style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '12px', cursor: 'pointer' }}>
196            <input
197              type="checkbox"
198              checked={showOptimized}
199              onChange={() => setShowOptimized(!showOptimized)}
200            />
201            Show virtualized list
202          </label>
203
204          {showOptimized ? (
205            <VirtualizedList items={filteredItems} />
206          ) : (
207            <div style={{
208              height: 200, overflow: 'auto', background: '#0d1b2a',
209              borderRadius: '8px', border: '1px solid #2a3f5f',
210            }}>
211              {filteredItems.map((item) => (
212                <div key={item.id} style={{
213                  padding: '8px 12px', borderBottom: '1px solid #1b2838',
214                  color: '#e0e1dd',
215                }}>
216                  {item.name} - value: {item.value}
217                </div>
218              ))}
219            </div>
220          )}
221        </div>
222      </Profiler>
223
224      {/* TODO: Add a section comparing the performance
225          of two approaches to state updates:
226          1. Multiple separate useState calls (temperature, pressure, oxygen)
227          2. One useState with an object { temperature, pressure, oxygen }
228          Use the Profiler component to measure the differences. */}
229    </div>
230  );
231}
232
233// --- Style ---
234const appStyle = {
235  background: '#0d1b2a', minHeight: '100vh', padding: '20px',
236  fontFamily: 'Arial, sans-serif', color: '#e0e1dd',
237};
238const sectionStyle = {
239  background: '#1b2838', borderRadius: '12px', padding: '20px',
240  maxWidth: '700px', margin: '16px auto', border: '1px solid #2a3f5f',
241};
242const headingStyle = { color: '#00d4ff', marginBottom: '8px' };
243const childStyle = {
244  display: 'flex', alignItems: 'center', gap: '10px',
245  padding: '10px', background: '#0d1b2a', borderRadius: '8px',
246  border: '1px solid #ff6b6b', marginBottom: '8px',
247};
248const renderBadge = {
249  background: '#ff6b6b', color: '#fff', padding: '2px 8px',
250  borderRadius: '12px', fontSize: '12px',
251};
252const btnStyle = {
253  marginLeft: 'auto', padding: '6px 14px', background: '#ff6b6b',
254  color: '#fff', border: 'none', borderRadius: '6px', cursor: 'pointer',
255};
256const btnAccent = {
257  padding: '8px 20px', background: '#ffd700', color: '#000',
258  border: 'none', borderRadius: '8px', cursor: 'pointer', fontWeight: 'bold',
259};
260const inputStyle = {
261  width: '100%', padding: '8px 12px', background: '#0d1b2a',
262  border: '1px solid #2a3f5f', borderRadius: '6px', color: '#e0e1dd',
263  fontSize: '14px', boxSizing: 'border-box',
264};
265
266export default App;

Spotted a mistake in this lesson?

Check yourself

Answer the questions from this lesson. Pick an answer to see right away whether it is correct.

  1. 1. What does React.memo() do and when should you use it?

  2. 2. What is React Profiler in React DevTools used for?

Hands-on tasks in the game

  • Code editor

    Dynamic Module Loading

  • Horizontal ordering

    Arrange the Suspense syntax with fallback UI:

  • Vertical ordering

    Arrange testing strategies by priority:

  • Code editor

    Custom hook useForm with validation

Useful articles