Staying Safe in a Concurrent World

Rate this content
Bookmark

With React 18 the long awaited concurrent features are now available to the public. While they technically do not introduce new restrictions about how we build our components, there are many patterns that previously worked but might now introduce subtle bugs in your apps. Let's re-learn the rules of React so that we can stay safe in this new concurrent world.

This talk has been presented at React Advanced Conference 2022, check out the latest edition of this React Conference.

FAQ

React 18 introduced concurrent features that allow developers to opt-in parts of their application into concurrent mode. This means that the entire application does not need to be concurrent mode-ready, allowing for a more gradual and controlled adoption.

The primary misconception is that the reconciliation phase is atomic, meaning it runs to completion without interruption. This was never a rule of React, and with the Fiber architecture introduced in React 16, the reconciliation phase can now be interrupted to handle user inputs or other tasks.

In React 18, even with concurrent features, the commit phase remains atomic. This means that once React starts updating the DOM, it completes all necessary updates to ensure a consistent state, avoiding the display of inconsistent data.

Reading values that might change outside of React, such as global variables or local storage, can lead to inconsistent states or 'tearing' in your application. This occurs because React might display different snapshots of state across different components.

React 16 introduced the Fiber architecture, replacing the stack reconciler. This change allowed React to split the rendering process into interruptible units of work, improving the handling of user inputs and other tasks during rendering.

Developers should use the built-in hook `useSyncExternalStore` for synchronizing external values with React, avoid mutating the outside world inside component functions, and rely on `useEffect` for side effects. Additionally, using modern state management libraries like ReduxToolkit or ReactQuery can help.

Pure functions in React components should not read values from the outside world or mutate the outside world. This means avoiding the use of `Math.random`, local storage, or refs during rendering, as React should control when rendering happens.

The change from async rendering to concurrent rendering was part of React's evolution to handle rendering in a more flexible and interruptible manner. This change allows React to adapt better to varying device and network conditions, improving user experience.

`useEffect` is designed to synchronize React with the outside world, making it the appropriate place to start network requests, add event listeners, or perform other side effects. This ensures that the rendering process remains pure and free from side effects.

Common issues include tearing, where parts of the application display inconsistent states, and problems with state synchronization. Using tools like `useSyncExternalStore` or modern state management libraries can help mitigate these issues.

Andreas Roth
Andreas Roth
22 min
24 Oct, 2022

Comments

Sign in or register to post your comment.

Video Summary and Transcription

This talk explores the implications of the new concurrent features in React 18 and how they impact developers. It discusses the core premise of React and the importance of pure function components. The talk also addresses misconceptions about React's rendering process and the prevention of tearing in applications. Additionally, it highlights the reconciliation and commit phases in React and the challenges of dependency management in state management libraries.

1. Introduction to React 18 Concurrent Features

Short description:

This talk explores the implications of the new concurrent features in React 18 and how they impact developers. The speaker, Andreas, shares his experience as a development lead in a software agency and highlights the importance of staying safe in a concurrent world.

I hope you're having an awesome conference so far. Maybe you even listened to a couple of talks mentioning the new concurrent features that were released in React 18 a couple of months ago. In this talk, we are not going into details about how these features work and what they are doing, but we want to take a look at the implications and ramifications that those features have on us as developers so that we can stay safe in a concurrent world of React.

Before we are going to dive into that, let me first tell you a bit about myself. My name is Andreas and I'm from Dresden in Germany, where I'm a development lead in a small software agency. Our job is to go into other software development companies and help the teams accelerate their software projects. We do that by using technologies like TypeScript React. So, this is exactly the stuff that I'm doing every day.

In this work, what we realized over the last couple of months is that there's lots of fear, uncertainty and doubt because of the new React agent release, the new rules and what you have to do to be concurrent mode-safe in your applications. And this is why I proposed this talk, so that you can lean back and stay safe in a concurrent world.

2. Evolution of React's Rendering Techniques

Short description:

Abramov introduced async rendering in 2018 to make React adapt to the user's device and ensure fast and responsive interactions. Since then, the release date was pushed back, and the name changed to concurrent rendering or concurrent mode. With React 18, concurrent features were introduced, allowing developers to opt-in specific parts of their application. The rules of React have not changed, but we are now starting to utilize them more effectively.

When we jumped back a couple of years ago, to 2018, then Abramov introduced async rendering. So, React should adapt to the user's device, fast interactions should feel instant and slow-end interactions should feel responsive. And the main technique was by splitting up the rendering process, so that we can pause, resume, do different updates, so that our application will stay fast and responsive, no matter the device or the network conditions.

Since then, lots have changed. So, for example, the release date has pushed back a bit, has been pushed back a bit, and the name changed from async rendering to concurrent rendering or concurrent mode. And then with React 18, the team made the awesome decision to not introduce a concurrent mode that switches all of your application in this new concurrent world, but they introduced concurrent features, so that you can opt in in tiny parts of your application into the concurrent features, so that your whole application must not be concurrent mode ready, but only parts of your application.

They even released a blog post back then, where they made certain changes to the React API to prepare this change for the future. So they removed component will mount, component will receive props and component will update, or replaced them with unsafe variants. This is so you as developers know that these methods are not really safe to use with concurrent features, but they can still live in your codebase as long as you don't use the concurrent features. You could say, the rules of React have changed since then. But it is not true. The rules of React have not changed since back then. This is the most important point of my presentation. The rules of React have not changed. We are only now starting to really make use of the same rules that have been present way back then.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

React Concurrency, Explained
React Summit 2023React Summit 2023
23 min
React Concurrency, Explained
Top Content
Watch video: React Concurrency, Explained
React 18's concurrent rendering, specifically the useTransition hook, optimizes app performance by allowing non-urgent updates to be processed without freezing the UI. However, there are drawbacks such as longer processing time for non-urgent updates and increased CPU usage. The useTransition hook works similarly to throttling or bouncing, making it useful for addressing performance issues caused by multiple small components. Libraries like React Query may require the use of alternative APIs to handle urgent and non-urgent updates effectively.
Understanding React’s Fiber Architecture
React Advanced Conference 2022React Advanced Conference 2022
29 min
Understanding React’s Fiber Architecture
Top Content
This Talk explores React's internal jargon, specifically fiber, which is an internal unit of work for rendering and committing. Fibers facilitate efficient updates to elements and play a crucial role in the reconciliation process. The work loop, complete work, and commit phase are essential steps in the rendering process. Understanding React's internals can help with optimizing code and pull request reviews. React 18 introduces the work loop sync and async functions for concurrent features and prioritization. Fiber brings benefits like async rendering and the ability to discard work-in-progress trees, improving user experience.
A Practical Guide for Migrating to Server Components
React Advanced Conference 2023React Advanced Conference 2023
28 min
A Practical Guide for Migrating to Server Components
Top Content
Watch video: A Practical Guide for Migrating to Server Components
React query version five is live and we'll be discussing the migration process to server components using Next.js and React Query. The process involves planning, preparing, and setting up server components, migrating pages, adding layouts, and moving components to the server. We'll also explore the benefits of server components such as reducing JavaScript shipping, enabling powerful caching, and leveraging the features of the app router. Additionally, we'll cover topics like handling authentication, rendering in server components, and the impact on server load and costs.
Server Components: The Epic Tale of Rendering UX
React Summit 2023React Summit 2023
26 min
Server Components: The Epic Tale of Rendering UX
Top Content
Watch video: Server Components: The Epic Tale of Rendering UX
This Talk introduces server components in React, which provide an intermediate format for rendering and offer advantages for both client-side and server-side rendering. Server components reduce bundle size on the client and improve search engine optimization. They abstract the rendering process, allowing for faster rendering and flexibility in choosing where to render components. While server components are still in the experimental stage, Next.js is a good starting point to try them out.
Inside Fiber: the in-depth overview you wanted a TLDR for
React Summit 2022React Summit 2022
27 min
Inside Fiber: the in-depth overview you wanted a TLDR for
This Talk explores the internals of React Fiber and its implications. It covers topics such as fibres and units of work, inspecting elements and parent matching, pattern matching and coroutines, and the influence of coroutines on concurrent React. The Talk also discusses effect handlers in React, handling side effects in components, and the history of effect handlers in React. It concludes by emphasizing the importance of understanding React internals and provides learning resources for further exploration.
Cracking the Concurrent Mode
React Advanced Conference 2021React Advanced Conference 2021
30 min
Cracking the Concurrent Mode
Sudhanshu Yadav discusses the incremental concurrent feature in React 18 and the need for concurrent mode to provide a better user experience. Time slicing is the key pattern enabling concurrent features. Background rendering and unit of work are used to achieve asynchronous rendering and eventual consistency. Concurrent mode introduces a new pattern called differing for immediate rendering and adjusting based on available resources. React provides APIs for deferred updates and transitions. Implementing concurrent mode APIs can be complex, but it offers benefits like avoiding update starvation and reusing work. Scheduling and slots are used to control execution and dynamic FPS control. Handling multiple transitions can be challenging, but the React 18 working group discussions provide insights into the team's efforts to improve the user experience.

Workshops on related topic

Concurrent Rendering Adventures in React 18
React Advanced Conference 2021React Advanced Conference 2021
132 min
Concurrent Rendering Adventures in React 18
Top Content
Featured WorkshopFree
Maurice de Beijer
Maurice de Beijer
With the release of React 18 we finally get the long awaited concurrent rendering. But how is that going to affect your application? What are the benefits of concurrent rendering in React? What do you need to do to switch to concurrent rendering when you upgrade to React 18? And what if you don’t want or can’t use concurrent rendering yet?

There are some behavior changes you need to be aware of! In this workshop we will cover all of those subjects and more.

Join me with your laptop in this interactive workshop. You will see how easy it is to switch to concurrent rendering in your React application. You will learn all about concurrent rendering, SuspenseList, the startTransition API and more.
Getting Started with Suspense and Concurrent Rendering in React
React Summit 2020React Summit 2020
125 min
Getting Started with Suspense and Concurrent Rendering in React
Featured Workshop
Maurice de Beijer
Maurice de Beijer
React keeps on evolving and making hard things easier for the average developer.
One case, where React was not particularly hard but very repetitive, is working with AJAX request. There is always the trinity of loading, success and possible error states that had to be handled each time. But no more as the `<Suspense />` component makes life much easier.
Another case is performance of larger and complex applications. Usually React is fast enough but with a large application rendering components can conflict with user interactions. Concurrent rendering will, mostly automatically, take care of this.
You will learn all about using <Suspense />, showing loading indicators and handling errors. You will see how easy it is to get started with concurrent rendering. You will make suspense even more capable combining it with concurrent rendering, the `useTransition()` hook and the <SuspenseList /> component.