reactjsDoc
Must Watch!
MustWatch
Getting Started
This page is an overview of the React documentation and related resources.
React is a JavaScript library for building user interfaces.
Learn what React is all about on our homepage or in the tutorial.
Try React
React has been designed from the start for gradual adoption, and you can use as little or as much React as you need. Whether you want to get a taste of React, add some interactivity to a simple HTML page, or start a complex React-powered app, the links in this section will help you get started.
Online Playgrounds
If you're interested in playing around with React, you can use an online code playground.
Try a Hello World template on CodePen, CodeSandbox, or Stackblitz.
If you prefer to use your own text editor, you can also download this HTML file, edit it, and open it from the local filesystem in your browser.
It does a slow runtime code transformation, so we'd only recommend using this for simple demos.
Add React to a Website
You can add React to an HTML page in one minute.
You can then either gradually expand its presence, or keep it contained to a few dynamic widgets.
Create a New React App
When starting a React project, a simple HTML page with script tags might still be the best option.
It only takes a minute to set up!
As your application grows, you might want to consider a more integrated setup.
There are several JavaScript toolchains we recommend for larger applications.
Each of them can work with little to no configuration and lets you take full advantage of the rich React ecosystem.
Learn how.
Learn React
People come to React from different backgrounds and with different learning styles.
Whether you prefer a more theoretical or a practical approach, we hope you'll find this section helpful.
Like any unfamiliar technology, React does have a learning curve.
With practice and some patience, you will get the hang of it.
First Examples
The React homepage contains a few small React examples with a live editor.
Even if you don't know anything about React yet, try changing their code and see how it affects the result.
React for Beginners
If you feel that the React documentation goes at a faster pace than you're comfortable with, check out this overview of React by Tania Rascia.
It introduces the most important React concepts in a detailed, beginner-friendly way.
Once you're done, give the documentation another try!
React for Designers
If you're coming from a design background, these resources are a great place to get started.
JavaScript Resources
The React documentation assumes some familiarity with programming in the JavaScript language.
You don't have to be an expert, but it's harder to learn both React and JavaScript at the same time.
We recommend going through this JavaScript overview to check your knowledge level.
It will take you between 30 minutes and an hour but you will feel more confident learning React.
Tip
Whenever you get confused by something in JavaScript, MDN and javascript.info are great websites to check.
There are also community support forums where you can ask for help.
Practical Tutorial
If you prefer to learn by doing, check out our practical tutorial.
In this tutorial, we build a tic-tac-toe game in React.
You might be tempted to skip it because you're not into building games ¡ª but give it a chance.
The techniques you'll learn in the tutorial are fundamental to building any React apps, and mastering it will give you a much deeper understanding.
Step-by-Step Guide
If you prefer to learn concepts step by step, our guide to main concepts is the best place to start.
Every next chapter in it builds on the knowledge introduced in the previous chapters so you won't miss anything as you go along.
Thinking in React
Many React users credit reading Thinking in React as the moment React finally ¡°clicked¡± for them.
It's probably the oldest React walkthrough but it's still just as relevant.
Recommended Courses
Sometimes people find third-party books and video courses more helpful than the official documentation.
We maintain a list of commonly recommended resources, some of which are free.
Advanced Concepts
Once you're comfortable with the main concepts and played with React a little bit, you might be interested in more advanced topics.
This section will introduce you to the powerful, but less commonly used React features like context and refs.
API Reference
This documentation section is useful when you want to learn more details about a particular React API.
For example, React.Component
API reference can provide you with details on how setState()
works, and what different lifecycle methods are useful for.
Glossary and FAQ
The glossary contains an overview of the most common terms you'll see in the React documentation.
There is also a FAQ section dedicated to short questions and answers about common topics, including making AJAX requests, component state, and file structure.
Staying Informed
The React blog is the official source for the updates from the React team.
Anything important, including release notes or deprecation notices, will be posted there first.
You can also follow the @reactjs account on Twitter, but you won't miss anything essential if you only read the blog.
Not every React release deserves its own blog post, but you can find a detailed changelog for every release in the CHANGELOG.md
file in the React repository, as well as on the Releases page.
Versioned Documentation
This documentation always reflects the latest stable version of React.
Since React 16, you can find older versions of the documentation on a separate page.
Note that documentation for past versions is snapshotted at the time of the release, and isn't being continuously updated.
Something Missing?
If something is missing in the documentation or if you found some part confusing, please file an issue for the documentation repository with your suggestions for improvement, or tweet at the @reactjs account.
We love hearing from you!
Add React to a Website
Use as little or as much React as you need.
React has been designed from the start for gradual adoption, and you can use as little or as much React as you need.
Perhaps you only want to add some ¡°sprinkles of interactivity¡± to an existing page.
React components are a great way to do that.
The majority of websites aren't, and don't need to be, single-page apps.
With a few lines of code and no build tooling, try React in a small part of your website.
You can then either gradually expand its presence, or keep it contained to a few dynamic widgets.
Add React in One Minute
In this section, we will show how to add a React component to an existing HTML page.
You can follow along with your own website, or create an empty HTML file to practice.
There will be no complicated tools or install requirements ¡ª to complete this section, you only need an internet connection, and a minute of your time.
Optional: Download the full example (2KB zipped)
Step 1: Add a DOM Container to the HTML
First, open the HTML page you want to edit.
Add an empty <div>
tag to mark the spot where you want to display something with React.
For example:
<!-- ...
existing HTML ...
-->
<div id="like_button_container"></div>
<!-- ...
existing HTML ...
-->
We gave this <div>
a unique id
HTML attribute.
This will allow us to find it from the JavaScript code later and display a React component inside of it.
Tip
You can place a ¡°container¡± <div>
like this anywhere inside the <body>
tag.
You may have as many independent DOM containers on one page as you need.
They are usually empty ¡ª React will replace any existing content inside DOM containers.
Step 2: Add the Script Tags
Next, add three <script>
tags to the HTML page right before the closing </body>
tag:
<!-- ...
other HTML ...
-->
<!-- Load React.
-->
<!-- Note: when deploying, replace "development.js" with "production.min.js".
-->
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
<!-- Load our React component.
-->
<script src="like_button.js"></script>
</body>
The first two tags load React.
The third one will load your component code.
Step 3: Create a React Component
Create a file called like_button.js
next to your HTML page.
Open this starter code and paste it into the file you created.
Tip
This code defines a React component called LikeButton
.
Don't worry if you don't understand it yet ¡ª we'll cover the building blocks of React later in our hands-on tutorial and main concepts guide.
For now, let's just get it showing on the screen!
After the starter code, add two lines to the bottom of like_button.js
:
// ...
the starter code you pasted ...
const domContainer = document.querySelector('#like_button_container');ReactDOM.render(e(LikeButton), domContainer);
These two lines of code find the <div>
we added to our HTML in the first step, and then display our ¡°Like¡± button React component inside of it.
That's It!
There is no step four.
You have just added the first React component to your website.
Check out the next sections for more tips on integrating React.
View the full example source code
Download the full example (2KB zipped)
Tip: Reuse a Component
Commonly, you might want to display React components in multiple places on the HTML page.
Here is an example that displays the ¡°Like¡± button three times and passes some data to it:
View the full example source code
Download the full example (2KB zipped)
Note
This strategy is mostly useful while React-powered parts of the page are isolated from each other.
Inside React code, it's easier to use component composition instead.
Tip: Minify JavaScript for Production
Before deploying your website to production, be mindful that unminified JavaScript can significantly slow down the page for your users.
If you already minify the application scripts, your site will be production-ready if you ensure that the deployed HTML loads the versions of React ending in production.min.js
:
<script src="https://unpkg.com/react@17/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js" crossorigin></script>
If you don't have a minification step for your scripts, here's one way to set it up.
Optional: Try React with JSX
In the examples above, we only relied on features that are natively supported by the browsers.
This is why we used a JavaScript function call to tell React what to display:
const e = React.createElement;
// Display a "Like" <button>
return e(
'button',
{ onClick: () => this.setState({ liked: true }) },
'Like'
);
However, React also offers an option to use JSX instead:
// Display a "Like" <button>
return (
<button onClick={() => this.setState({ liked: true })}>
Like
</button>
);
These two code snippets are equivalent.
While JSX is completely optional, many people find it helpful for writing UI code ¡ª both with React and with other libraries.
You can play with JSX using this online converter.
Quickly Try JSX
The quickest way to try JSX in your project is to add this <script>
tag to your page:
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
Now you can use JSX in any <script>
tag by adding type="text/babel"
attribute to it.
Here is an example HTML file with JSX that you can download and play with.
This approach is fine for learning and creating simple demos.
However, it makes your website slow and isn't suitable for production.
When you're ready to move forward, remove this new <script>
tag and the type="text/babel"
attributes you've added.
Instead, in the next section you will set up a JSX preprocessor to convert all your <script>
tags automatically.
Add JSX to a Project
Adding JSX to a project doesn't require complicated tools like a bundler or a development server.
Essentially, adding JSX is a lot like adding a CSS preprocessor. The only requirement is to have Node.js installed on your computer.
Go to your project folder in the terminal, and paste these two commands:
-
Step 1: Run
npm init -y
(if it fails, here's a fix)
-
Step 2: Run
npm install babel-cli@6 babel-preset-react-app@3
Tip
We're using npm here only to install the JSX preprocessor; you won't need it for anything else.
Both React and the application code can stay as <script>
tags with no changes.
Congratulations! You just added a production-ready JSX setup to your project.
Run JSX Preprocessor
Create a folder called src
and run this terminal command:
npx babel --watch src --out-dir .
--presets react-app/prod
Note
npx
is not a typo ¡ª it's a package runner tool that comes with npm 5.2+.
If you see an error message saying ¡°You have mistakenly installed the babel
package¡±, you might have missed the previous step.
Perform it in the same folder, and then try again.
Don't wait for it to finish ¡ª this command starts an automated watcher for JSX.
If you now create a file called src/like_button.js
with this JSX starter code, the watcher will create a preprocessed like_button.js
with the plain JavaScript code suitable for the browser.
When you edit the source file with JSX, the transform will re-run automatically.
As a bonus, this also lets you use modern JavaScript syntax features like classes without worrying about breaking older browsers.
The tool we just used is called Babel, and you can learn more about it from its documentation.
If you notice that you're getting comfortable with build tools and want them to do more for you, the next section describes some of the most popular and approachable toolchains.
If not ¡ª those script tags will do just fine!
Create a New React App
Use an integrated toolchain for the best user and developer experience.
This page describes a few popular React toolchains which help with tasks like:
- Scaling to many files and components.
- Using third-party libraries from npm.
- Detecting common mistakes early.
- Live-editing CSS and JS in development.
- Optimizing the output for production.
The toolchains recommended on this page don't require configuration to get started.
You Might Not Need a Toolchain
If you don't experience the problems described above or don't feel comfortable using JavaScript tools yet, consider adding React as a plain <script>
tag on an HTML page, optionally with JSX.
This is also the easiest way to integrate React into an existing website. You can always add a larger toolchain if you find it helpful!
Recommended Toolchains
The React team primarily recommends these solutions:
- If you're learning React or creating a new single-page app, use Create React App.
- If you're building a server-rendered website with Node.js, try Next.js.
- If you're building a static content-oriented website, try Gatsby.
- If you're building a component library or integrating with an existing codebase, try More Flexible Toolchains.
Create React App
Create React App is a comfortable environment for learning React, and is the best way to start building a new single-page application in React.
It sets up your development environment so that you can use the latest JavaScript features, provides a nice developer experience, and optimizes your app for production.
You'll need to have Node >= 10.16 and npm >= 5.6 on your machine.
To create a project, run:
npx create-react-app my-app
cd my-app
npm start
Note
npx
on the first line is not a typo ¡ª it's a package runner tool that comes with npm 5.2+.
Create React App doesn't handle backend logic or databases; it just creates a frontend build pipeline, so you can use it with any backend you want.
Under the hood, it uses Babel and webpack, but you don't need to know anything about them.
When you're ready to deploy to production, running npm run build
will create an optimized build of your app in the build
folder.
You can learn more about Create React App from its README and the User Guide.
Next.js
Next.js is a popular and lightweight framework for static and server rendered applications built with React.
It includes styling and routing solutions out of the box, and assumes that you're using Node.js as the server environment.
Learn Next.js from its official guide.
Gatsby
Gatsby is the best way to create static websites with React.
It lets you use React components, but outputs pre-rendered HTML and CSS to guarantee the fastest load time.
Learn Gatsby from its official guide and a gallery of starter kits.
More Flexible Toolchains
The following toolchains offer more flexibility and choice.
We recommend them to more experienced users:
-
Neutrino combines the power of webpack with the simplicity of presets, and includes a preset for React apps and React components.
-
Nx is a toolkit for full-stack monorepo development, with built-in support for React, Next.js, Express, and more.
-
Parcel is a fast, zero configuration web application bundler that works with React.
-
Razzle is a server-rendering framework that doesn't require any configuration, but offers more flexibility than Next.js.
Creating a Toolchain from Scratch
A JavaScript build toolchain typically consists of:
- A package manager, such as Yarn or npm.
It lets you take advantage of a vast ecosystem of third-party packages, and easily install or update them.
- A bundler, such as webpack or Parcel.
It lets you write modular code and bundle it together into small packages to optimize load time.
- A compiler such as Babel.
It lets you write modern JavaScript code that still works in older browsers.
If you prefer to set up your own JavaScript toolchain from scratch, check out this guide that re-creates some of the Create React App functionality.
Don't forget to ensure your custom toolchain is correctly set up for production.
CDN Links
Both React and ReactDOM are available over a CDN.
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
The versions above are only meant for development, and are not suitable for production.
Minified and optimized production versions of React are available at:
<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
To load a specific version of react
and react-dom
, replace 17
with the version number.
Why the crossorigin
Attribute?
If you serve React from a CDN, we recommend to keep the crossorigin
attribute set:
<script crossorigin src="..."></script>
We also recommend to verify that the CDN you are using sets the Access-Control-Allow-Origin: *
HTTP header:
This enables a better error handling experience in React 16 and later.
Release Channels
React relies on a thriving open source community to file bug reports, open pull requests, and submit RFCs.
To encourage feedback we sometimes share special builds of React that include unreleased features.
This document will be most relevant to developers who work on frameworks, libraries, or developer tooling.
Developers who use React primarily to build user-facing applications should not need to worry about our prerelease channels.
Each of React's release channels is designed for a distinct use case:
-
Latest is for stable, semver React releases.
It's what you get when you install React from npm.
This is the channel you're already using today.
Use this for all user-facing React applications.
-
Next tracks the master branch of the React source code repository.
Think of these as release candidates for the next minor semver release.
Use this for integration testing between React and third party projects.
-
Experimental includes experimental APIs and features that aren't available in the stable releases.
These also track the master branch, but with additional feature flags turned on.
Use this to try out upcoming features before they are released.
All releases are published to npm, but only Latest uses semantic versioning.
Prereleases (those in the Next and Experimental channels) have versions generated from a hash of their contents, e.g.
0.0.0-1022ee0ec
for Next and 0.0.0-experimental-1022ee0ec
for Experimental.
The only officially supported release channel for user-facing applications is Latest.
Next and Experimental releases are provided for testing purposes only, and we provide no guarantees that behavior won't change between releases.
They do not follow the semver protocol that we use for releases from Latest.
By publishing prereleases to the same registry that we use for stable releases, we are able to take advantage of the many tools that support the npm workflow, like unpkg and CodeSandbox.
Latest Channel
Latest is the channel used for stable React releases.
It corresponds to the latest
tag on npm.
It is the recommended channel for all React apps that are shipped to real users.
If you're not sure which channel you should use, it's Latest. If you're a React developer, this is what you're already using.
You can expect updates to Latest to be extremely stable.
Versions follow the semantic versioning scheme.
Learn more about our commitment to stability and incremental migration in our versioning policy.
Next Channel
The Next channel is a prerelease channel that tracks the master branch of the React repository.
We use prereleases in the Next channel as release candidates for the Latest channel.
You can think of Next as a superset of Latest that is updated more frequently.
The degree of change between the most recent Next release and the most recent Latest release is approximately the same as you would find between two minor semver releases.
However, the Next channel does not conform to semantic versioning. You should expect occasional breaking changes between successive releases in the Next channel.
Do not use prereleases in user-facing applications.
Releases in Next are published with the next
tag on npm.
Versions are generated from a hash of the build's contents, e.g.
0.0.0-1022ee0ec
.
Using the Next Channel for Integration Testing
The Next channel is designed to support integration testing between React and other projects.
All changes to React go through extensive internal testing before they are released to the public.
However, there are a myriad of environments and configurations used throughout the React ecosystem, and it's not possible for us to test against every single one.
If you're the author of a third party React framework, library, developer tool, or similar infrastructure-type project, you can help us keep React stable for your users and the entire React community by periodically running your test suite against the most recent changes.
If you're interested, follow these steps:
- Set up a cron job using your preferred continuous integration platform.
Cron jobs are supported by both CircleCI and Travis CI.
-
In the cron job, update your React packages to the most recent React release in the Next channel, using
next
tag on npm.
Using the npm cli:
npm update react@next react-dom@next
Or yarn:
yarn upgrade react@next react-dom@next
- Run your test suite against the updated packages.
- If everything passes, great! You can expect that your project will work with the next minor React release.
- If something breaks unexpectedly, please let us know by filing an issue.
A project that uses this workflow is Next.js.
(No pun intended! Seriously!) You can refer to their CircleCI configuration as an example.
Experimental Channel
Like Next, the Experimental channel is a prerelease channel that tracks the master branch of the React repository.
Unlike Next, Experimental releases include additional features and APIs that are not ready for wider release.
Usually, an update to Next is accompanied by a corresponding update to Experimental.
They are based on the same source revision, but are built using a different set of feature flags.
Experimental releases may be significantly different than releases to Next and Latest.
Do not use Experimental releases in user-facing applications. You should expect frequent breaking changes between releases in the Experimental channel.
Releases in Experimental are published with the experimental
tag on npm.
Versions are generated from a hash of the build's contents, e.g.
0.0.0-experimental-1022ee0ec
.
What Goes Into an Experimental Release?
Experimental features are ones that are not ready to be released to the wider public, and may change drastically before they are finalized.
Some experiments may never be finalized ¡ª the reason we have experiments is to test the viability of proposed changes.
For example, if the Experimental channel had existed when we announced Hooks, we would have released Hooks to the Experimental channel weeks before they were available in Latest.
You may find it valuable to run integration tests against Experimental.
This is up to you.
However, be advised that Experimental is even less stable than Next.
We do not guarantee any stability between Experimental releases.
How Can I Learn More About Experimental Features?
Experimental features may or may not be documented.
Usually, experiments aren't documented until they are close to shipping in Next or Latest.
If a feature is not documented, they may be accompanied by an RFC.
We will post to the React blog when we're ready to announce new experiments, but that doesn't mean we will publicize every experiment.
You can always refer to our public GitHub repository's history for a comprehensive list of changes.
Hello World
The smallest React example looks like this:
ReactDOM.render(
<h2>Hello, world!</h2>,
document.getElementById('root')
);
It displays a heading saying ¡°Hello, world!¡± on the page.
Try it on CodePen
Click the link above to open an online editor.
Feel free to make some changes, and see how they affect the output.
Most pages in this guide will have editable examples like this one.
How to Read This Guide
In this guide, we will examine the building blocks of React apps: elements and components.
Once you master them, you can create complex apps from small reusable pieces.
Tip
This guide is designed for people who prefer learning concepts step by step.
If you prefer to learn by doing, check out our practical tutorial.
You might find this guide and the tutorial complementary to each other.
This is the first chapter in a step-by-step guide about main React concepts.
You can find a list of all its chapters in the navigation sidebar.
If you're reading this from a mobile device, you can access the navigation by pressing the button in the bottom right corner of your screen.
Every chapter in this guide builds on the knowledge introduced in earlier chapters.
You can learn most of React by reading the ¡°Main Concepts¡± guide chapters in the order they appear in the sidebar. For example, ¡°Introducing JSX¡± is the next chapter after this one.
Knowledge Level Assumptions
React is a JavaScript library, and so we'll assume you have a basic understanding of the JavaScript language.
If you don't feel very confident, we recommend going through a JavaScript tutorial to check your knowledge level and enable you to follow along this guide without getting lost.
It might take you between 30 minutes and an hour, but as a result you won't have to feel like you're learning both React and JavaScript at the same time.
Note
This guide occasionally uses some of the newer JavaScript syntax in the examples.
If you haven't worked with JavaScript in the last few years, these three points should get you most of the way.
Let's Get Started!
Keep scrolling down, and you'll find the link to the next chapter of this guide right before the website footer.
Introducing JSX
Consider this variable declaration:
const element = <h2>Hello, world!</h2>;
This funny tag syntax is neither a string nor HTML.
It is called JSX, and it is a syntax extension to JavaScript.
We recommend using it with React to describe what the UI should look like.
JSX may remind you of a template language, but it comes with the full power of JavaScript.
JSX produces React ¡°elements¡±.
We will explore rendering them to the DOM in the next section.
Below, you can find the basics of JSX necessary to get you started.
Why JSX?
React embraces the fact that rendering logic is inherently coupled with other UI logic: how events are handled, how the state changes over time, and how the data is prepared for display.
Instead of artificially separating technologies by putting markup and logic in separate files, React separates concerns with loosely coupled units called ¡°components¡± that contain both.
We will come back to components in a further section, but if you're not yet comfortable putting markup in JS, this talk might convince you otherwise.
React doesn't require using JSX, but most people find it helpful as a visual aid when working with UI inside the JavaScript code.
It also allows React to show more useful error and warning messages.
With that out of the way, let's get started!
Embedding Expressions in JSX
In the example below, we declare a variable called name
and then use it inside JSX by wrapping it in curly braces:
const name = 'Josh Perez';const element = <h2>Hello, {name}</h2>;
ReactDOM.render(
element,
document.getElementById('root')
);
You can put any valid JavaScript expression inside the curly braces in JSX.
For example, 2 + 2
, user.firstName
, or formatName(user)
are all valid JavaScript expressions.
In the example below, we embed the result of calling a JavaScript function, formatName(user)
, into an <h2>
element.
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
const element = (
<h2>
Hello, {formatName(user)}! </h2>
);
ReactDOM.render(
element,
document.getElementById('root')
);
Try it on CodePen
We split JSX over multiple lines for readability.
While it isn't required, when doing this, we also recommend wrapping it in parentheses to avoid the pitfalls of automatic semicolon insertion.
JSX is an Expression Too
After compilation, JSX expressions become regular JavaScript function calls and evaluate to JavaScript objects.
This means that you can use JSX inside of if
statements and for
loops, assign it to variables, accept it as arguments, and return it from functions:
function getGreeting(user) {
if (user) {
return <h2>Hello, {formatName(user)}!</h2>; }
return <h2>Hello, Stranger.</h2>;}
Specifying Attributes with JSX
You may use quotes to specify string literals as attributes:
const element = <div tabIndex="0"></div>;
You may also use curly braces to embed a JavaScript expression in an attribute:
const element = <img src={user.avatarUrl}></img>;
Don't put quotes around curly braces when embedding a JavaScript expression in an attribute.
You should either use quotes (for string values) or curly braces (for expressions), but not both in the same attribute.
Warning:
Since JSX is closer to JavaScript than to HTML, React DOM uses camelCase
property naming convention instead of HTML attribute names.
For example, class
becomes className
in JSX, and tabindex
becomes tabIndex
.
Specifying Children with JSX
If a tag is empty, you may close it immediately with />
, like XML:
const element = <img src={user.avatarUrl} />;
JSX tags may contain children:
const element = (
<div>
<h2>Hello!</h2>
<h3>Good to see you here.</h3>
</div>
);
JSX Prevents Injection Attacks
It is safe to embed user input in JSX:
const title = response.potentiallyMaliciousInput;
// This is safe:
const element = <h2>{title}</h2>;
By default, React DOM escapes any values embedded in JSX before rendering them.
Thus it ensures that you can never inject anything that's not explicitly written in your application.
Everything is converted to a string before being rendered.
This helps prevent XSS (cross-site-scripting) attacks.
JSX Represents Objects
Babel compiles JSX down to React.createElement()
calls.
These two examples are identical:
const element = (
<h2 className="greeting">
Hello, world!
</h2>
);
const element = React.createElement(
'h2',
{className: 'greeting'},
'Hello, world!'
);
React.createElement()
performs a few checks to help you write bug-free code but essentially it creates an object like this:
// Note: this structure is simplified
const element = {
type: 'h2',
props: {
className: 'greeting',
children: 'Hello, world!'
}
};
These objects are called ¡°React elements¡±.
You can think of them as descriptions of what you want to see on the screen.
React reads these objects and uses them to construct the DOM and keep it up to date.
We will explore rendering React elements to the DOM in the next section.
Tip:
We recommend using the ¡°Babel¡± language definition for your editor of choice so that both ES6 and JSX code is properly highlighted.
Rendering Elements
Elements are the smallest building blocks of React apps.
An element describes what you want to see on the screen:
const element = <h2>Hello, world</h2>;
Unlike browser DOM elements, React elements are plain objects, and are cheap to create.
React DOM takes care of updating the DOM to match the React elements.
Note:
One might confuse elements with a more widely known concept of ¡°components¡±.
We will introduce components in the next section.
Elements are what components are ¡°made of¡±, and we encourage you to read this section before jumping ahead.
Rendering an Element into the DOM
Let's say there is a <div>
somewhere in your HTML file:
<div>
We call this a ¡°root¡± DOM node because everything inside it will be managed by React DOM.
Applications built with just React usually have a single root DOM node.
If you are integrating React into an existing app, you may have as many isolated root DOM nodes as you like.
To render a React element into a root DOM node, pass both to ReactDOM.render()
:
const element = <h2>Hello, world</h2>;
ReactDOM.render(element, document.getElementById('root'));
Try it on CodePen
It displays ¡°Hello, world¡± on the page.
Updating the Rendered Element
React elements are immutable.
Once you create an element, you can't change its children or attributes.
An element is like a single frame in a movie: it represents the UI at a certain point in time.
With our knowledge so far, the only way to update the UI is to create a new element, and pass it to ReactDOM.render()
.
Consider this ticking clock example:
function tick() {
const element = (
<div>
<h2>Hello, world!</h2>
<h3>It is {new Date().toLocaleTimeString()}.</h3>
</div>
);
ReactDOM.render(element, document.getElementById('root'));}
setInterval(tick, 1000);
Try it on CodePen
It calls ReactDOM.render()
every second from a setInterval()
callback.
Note:
In practice, most React apps only call ReactDOM.render()
once.
In the next sections we will learn how such code gets encapsulated into stateful components.
We recommend that you don't skip topics because they build on each other.
React Only Updates What's Necessary
React DOM compares the element and its children to the previous one, and only applies the DOM updates necessary to bring the DOM to the desired state.
You can verify by inspecting the last example with the browser tools:
Even though we create an element describing the whole UI tree on every tick, only the text node whose contents have changed gets updated by React DOM.
In our experience, thinking about how the UI should look at any given moment, rather than how to change it over time, eliminates a whole class of bugs.
Components and Props
Components let you split the UI into independent, reusable pieces, and think about each piece in isolation.
This page provides an introduction to the idea of components.
You can find a detailed component API reference here.
Conceptually, components are like JavaScript functions.
They accept arbitrary inputs (called ¡°props¡±) and return React elements describing what should appear on the screen.
Function and Class Components
The simplest way to define a component is to write a JavaScript function:
function Welcome(props) {
return <h2>Hello, {props.name}</h2>;
}
This function is a valid React component because it accepts a single ¡°props¡± (which stands for properties) object argument with data and returns a React element.
We call such components ¡°function components¡± because they are literally JavaScript functions.
You can also use an ES6 class to define a component:
class Welcome extends React.Component {
render() {
return <h2>Hello, {this.props.name}</h2>;
}
}
The above two components are equivalent from React's point of view.
Function and Class components both have some additional features that we will discuss in the next sections.
Rendering a Component
Previously, we only encountered React elements that represent DOM tags:
const element = <div />;
However, elements can also represent user-defined components:
const element = <Welcome name="Sara" />;
When React sees an element representing a user-defined component, it passes JSX attributes and children to this component as a single object.
We call this object ¡°props¡±.
For example, this code renders ¡°Hello, Sara¡± on the page:
function Welcome(props) { return <h2>Hello, {props.name}</h2>;
}
const element = <Welcome name="Sara" />;ReactDOM.render(
element,
document.getElementById('root')
);
Try it on CodePen
Let's recap what happens in this example:
- We call
ReactDOM.render()
with the <Welcome name="Sara" />
element.
- React calls the
Welcome
component with {name: 'Sara'}
as the props.
- Our
Welcome
component returns a <h2>Hello, Sara</h2>
element as the result.
- React DOM efficiently updates the DOM to match
<h2>Hello, Sara</h2>
.
Note: Always start component names with a capital letter.
React treats components starting with lowercase letters as DOM tags.
For example, <div />
represents an HTML div tag, but <Welcome />
represents a component and requires Welcome
to be in scope.
To learn more about the reasoning behind this convention, please read JSX In Depth.
Composing Components
Components can refer to other components in their output.
This lets us use the same component abstraction for any level of detail.
A button, a form, a dialog, a screen: in React apps, all those are commonly expressed as components.
For example, we can create an App
component that renders Welcome
many times:
function Welcome(props) {
return <h2>Hello, {props.name}</h2>;
}
function App() {
return (
<div>
<Welcome name="Sara" /> <Welcome name="Cahal" /> <Welcome name="Edite" /> </div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
Try it on CodePen
Typically, new React apps have a single App
component at the very top.
However, if you integrate React into an existing app, you might start bottom-up with a small component like Button
and gradually work your way to the top of the view hierarchy.
Extracting Components
Don't be afraid to split components into smaller components.
For example, consider this Comment
component:
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<img className="Avatar"
src={props.author.avatarUrl}
alt={props.author.name}
/>
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
Try it on CodePen
It accepts author
(an object), text
(a string), and date
(a date) as props, and describes a comment on a social media website.
This component can be tricky to change because of all the nesting, and it is also hard to reuse individual parts of it.
Let's extract a few components from it.
First, we will extract Avatar
:
function Avatar(props) {
return (
<img className="Avatar" src={props.user.avatarUrl} alt={props.user.name} /> );
}
The Avatar
doesn't need to know that it is being rendered inside a Comment
.
This is why we have given its prop a more generic name: user
rather than author
.
We recommend naming props from the component's own point of view rather than the context in which it is being used.
We can now simplify Comment
a tiny bit:
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<Avatar user={props.author} /> <div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
Next, we will extract a UserInfo
component that renders an Avatar
next to the user's name:
function UserInfo(props) {
return (
<div className="UserInfo"> <Avatar user={props.user} /> <div className="UserInfo-name"> {props.user.name} </div> </div> );
}
This lets us simplify Comment
even further:
function Comment(props) {
return (
<div className="Comment">
<UserInfo user={props.author} /> <div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
Try it on CodePen
Extracting components might seem like grunt work at first, but having a palette of reusable components pays off in larger apps.
A good rule of thumb is that if a part of your UI is used several times (Button
, Panel
, Avatar
), or is complex enough on its own (App
, FeedStory
, Comment
), it is a good candidate to be extracted to a separate component.
Props are Read-Only
Whether you declare a component as a function or a class, it must never modify its own props.
Consider this sum
function:
function sum(a, b) {
return a + b;
}
Such functions are called ¡°pure¡± because they do not attempt to change their inputs, and always return the same result for the same inputs.
In contrast, this function is impure because it changes its own input:
function withdraw(account, amount) {
account.total -= amount;
}
React is pretty flexible but it has a single strict rule:
All React components must act like pure functions with respect to their props.
Of course, application UIs are dynamic and change over time.
In the next section, we will introduce a new concept of ¡°state¡±.
State allows React components to change their output over time in response to user actions, network responses, and anything else, without violating this rule.
State and Lifecycle
This page introduces the concept of state and lifecycle in a React component.
You can find a detailed component API reference here.
Consider the ticking clock example from one of the previous sections.
In Rendering Elements, we have only learned one way to update the UI.
We call ReactDOM.render()
to change the rendered output:
function tick() {
const element = (
<div>
<h2>Hello, world!</h2>
<h3>It is {new Date().toLocaleTimeString()}.</h3>
</div>
);
ReactDOM.render( element, document.getElementById('root') );}
setInterval(tick, 1000);
Try it on CodePen
In this section, we will learn how to make the Clock
component truly reusable and encapsulated.
It will set up its own timer and update itself every second.
We can start by encapsulating how the clock looks:
function Clock(props) {
return (
<div> <h2>Hello, world!</h2> <h3>It is {props.date.toLocaleTimeString()}.</h3> </div> );
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />, document.getElementById('root')
);
}
setInterval(tick, 1000);
Try it on CodePen
However, it misses a crucial requirement: the fact that the Clock
sets up a timer and updates the UI every second should be an implementation detail of the Clock
.
Ideally we want to write this once and have the Clock
update itself:
ReactDOM.render(
<Clock />, document.getElementById('root')
);
To implement this, we need to add ¡°state¡± to the Clock
component.
State is similar to props, but it is private and fully controlled by the component.
Converting a Function to a Class
You can convert a function component like Clock
to a class in five steps:
- Create an ES6 class, with the same name, that extends
React.Component
.
- Add a single empty method to it called
render()
.
- Move the body of the function into the
render()
method.
- Replace
props
with this.props
in the render()
body.
- Delete the remaining empty function declaration.
class Clock extends React.Component {
render() {
return (
<div>
<h2>Hello, world!</h2>
<h3>It is {this.props.date.toLocaleTimeString()}.</h3>
</div>
);
}
}
Try it on CodePen
Clock
is now defined as a class rather than a function.
The render
method will be called each time an update happens, but as long as we render <Clock />
into the same DOM node, only a single instance of the Clock
class will be used.
This lets us use additional features such as local state and lifecycle methods.
Adding Local State to a Class
We will move the date
from props to state in three steps:
- Replace
this.props.date
with this.state.date
in the render()
method:
class Clock extends React.Component {
render() {
return (
<div>
<h2>Hello, world!</h2>
<h3>It is {this.state.date.toLocaleTimeString()}.</h3> </div>
);
}
}
- Add a class constructor that assigns the initial
this.state
:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()}; }
render() {
return (
<div>
<h2>Hello, world!</h2>
<h3>It is {this.state.date.toLocaleTimeString()}.</h3>
</div>
);
}
}
Note how we pass props
to the base constructor:
constructor(props) {
super(props); this.state = {date: new Date()};
}
Class components should always call the base constructor with props
.
- Remove the
date
prop from the <Clock />
element:
ReactDOM.render(
<Clock />, document.getElementById('root')
);
We will later add the timer code back to the component itself.
The result looks like this:
class Clock extends React.Component {
constructor(props) { super(props); this.state = {date: new Date()}; }
render() {
return (
<div>
<h2>Hello, world!</h2>
<h3>It is {this.state.date.toLocaleTimeString()}.</h3> </div>
);
}
}
ReactDOM.render(
<Clock />, document.getElementById('root')
);
Try it on CodePen
Next, we'll make the Clock
set up its own timer and update itself every second.
Adding Lifecycle Methods to a Class
In applications with many components, it's very important to free up resources taken by the components when they are destroyed.
We want to set up a timer whenever the Clock
is rendered to the DOM for the first time.
This is called ¡°mounting¡± in React.
We also want to clear that timer whenever the DOM produced by the Clock
is removed.
This is called ¡°unmounting¡± in React.
We can declare special methods on the component class to run some code when a component mounts and unmounts:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() { }
componentWillUnmount() { }
render() {
return (
<div>
<h2>Hello, world!</h2>
<h3>It is {this.state.date.toLocaleTimeString()}.</h3>
</div>
);
}
}
These methods are called ¡°lifecycle methods¡±.
The componentDidMount()
method runs after the component output has been rendered to the DOM.
This is a good place to set up a timer:
componentDidMount() {
this.timerID = setInterval( () => this.tick(), 1000 ); }
Note how we save the timer ID right on this
(this.timerID
).
While this.props
is set up by React itself and this.state
has a special meaning, you are free to add additional fields to the class manually if you need to store something that doesn't participate in the data flow (like a timer ID).
We will tear down the timer in the componentWillUnmount()
lifecycle method:
componentWillUnmount() {
clearInterval(this.timerID); }
Finally, we will implement a method called tick()
that the Clock
component will run every second.
It will use this.setState()
to schedule updates to the component local state:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() { this.setState({ date: new Date() }); }
render() {
return (
<div>
<h2>Hello, world!</h2>
<h3>It is {this.state.date.toLocaleTimeString()}.</h3>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
Try it on CodePen
Now the clock ticks every second.
Let's quickly recap what's going on and the order in which the methods are called:
- When
<Clock />
is passed to ReactDOM.render()
, React calls the constructor of the Clock
component.
Since Clock
needs to display the current time, it initializes this.state
with an object including the current time.
We will later update this state.
- React then calls the
Clock
component's render()
method.
This is how React learns what should be displayed on the screen.
React then updates the DOM to match the Clock
's render output.
- When the
Clock
output is inserted in the DOM, React calls the componentDidMount()
lifecycle method.
Inside it, the Clock
component asks the browser to set up a timer to call the component's tick()
method once a second.
- Every second the browser calls the
tick()
method.
Inside it, the Clock
component schedules a UI update by calling setState()
with an object containing the current time.
Thanks to the setState()
call, React knows the state has changed, and calls the render()
method again to learn what should be on the screen.
This time, this.state.date
in the render()
method will be different, and so the render output will include the updated time.
React updates the DOM accordingly.
- If the
Clock
component is ever removed from the DOM, React calls the componentWillUnmount()
lifecycle method so the timer is stopped.
Using State Correctly
There are three things you should know about setState()
.
Do Not Modify State Directly
For example, this will not re-render a component:
// Wrong
this.state.comment = 'Hello';
Instead, use setState()
:
// Correct
this.setState({comment: 'Hello'});
The only place where you can assign this.state
is the constructor.
State Updates May Be Asynchronous
React may batch multiple setState()
calls into a single update for performance.
Because this.props
and this.state
may be updated asynchronously, you should not rely on their values for calculating the next state.
For example, this code may fail to update the counter:
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
To fix it, use a second form of setState()
that accepts a function rather than an object.
That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
We used an arrow function above, but it also works with regular functions:
// Correct
this.setState(function(state, props) {
return {
counter: state.counter + props.increment
};
});
State Updates are Merged
When you call setState()
, React merges the object you provide into the current state.
For example, your state may contain several independent variables:
constructor(props) {
super(props);
this.state = {
posts: [], comments: [] };
}
Then you can update them independently with separate setState()
calls:
componentDidMount() {
fetchPosts().then(response => {
this.setState({
posts: response.posts });
});
fetchComments().then(response => {
this.setState({
comments: response.comments });
});
}
The merging is shallow, so this.setState({comments})
leaves this.state.posts
intact, but completely replaces this.state.comments
.
The Data Flows Down
Neither parent nor child components can know if a certain component is stateful or stateless, and they shouldn't care whether it is defined as a function or a class.
This is why state is often called local or encapsulated.
It is not accessible to any component other than the one that owns and sets it.
A component may choose to pass its state down as props to its child components:
<FormattedDate date={this.state.date} />
The FormattedDate
component would receive the date
in its props and wouldn't know whether it came from the Clock
's state, from the Clock
's props, or was typed by hand:
function FormattedDate(props) {
return <h3>It is {props.date.toLocaleTimeString()}.</h3>;
}
Try it on CodePen
This is commonly called a ¡°top-down¡± or ¡°unidirectional¡± data flow.
Any state is always owned by some specific component, and any data or UI derived from that state can only affect components ¡°below¡± them in the tree.
If you imagine a component tree as a waterfall of props, each component's state is like an additional water source that joins it at an arbitrary point but also flows down.
To show that all components are truly isolated, we can create an App
component that renders three <Clock>
s:
function App() {
return (
<div>
<Clock /> <Clock /> <Clock /> </div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
Try it on CodePen
Each Clock
sets up its own timer and updates independently.
In React apps, whether a component is stateful or stateless is considered an implementation detail of the component that may change over time.
You can use stateless components inside stateful components, and vice versa.
Handling Events
Handling events with React elements is very similar to handling events on DOM elements.
There are some syntax differences:
- React events are named using camelCase, rather than lowercase.
- With JSX you pass a function as the event handler, rather than a string.
For example, the HTML:
<button onclick="activateLasers()">
Activate Lasers
</button>
is slightly different in React:
<button onClick={activateLasers}> Activate Lasers
</button>
Another difference is that you cannot return false
to prevent default behavior in React.
You must call preventDefault
explicitly.
For example, with plain HTML, to prevent the default link behavior of opening a new page, you can write:
<a href="#" onclick="console.log('The link was clicked.'); return false">
Click me
</a>
In React, this could instead be:
function ActionLink() {
function handleClick(e) { e.preventDefault(); console.log('The link was clicked.'); }
return (
<a href="#" onClick={handleClick}> Click me
</a>
);
}
Here, e
is a synthetic event.
React defines these synthetic events according to the W3C spec, so you don't need to worry about cross-browser compatibility.
React events do not work exactly the same as native events.
See the SyntheticEvent
reference guide to learn more.
When using React, you generally don't need to call addEventListener
to add listeners to a DOM element after it is created.
Instead, just provide a listener when the element is initially rendered.
When you define a component using an ES6 class, a common pattern is for an event handler to be a method on the class.
For example, this Toggle
component renders a button that lets the user toggle between ¡°ON¡± and ¡°OFF¡± states:
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// This binding is necessary to make `this` work in the callback this.handleClick = this.handleClick.bind(this); }
handleClick() { this.setState(state => ({ isToggleOn: !state.isToggleOn })); }
render() {
return (
<button onClick={this.handleClick}> {this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
Try it on CodePen
You have to be careful about the meaning of this
in JSX callbacks.
In JavaScript, class methods are not bound by default.
If you forget to bind this.handleClick
and pass it to onClick
, this
will be undefined
when the function is actually called.
This is not React-specific behavior; it is a part of how functions work in JavaScript.
Generally, if you refer to a method without ()
after it, such as onClick={this.handleClick}
, you should bind that method.
If calling bind
annoys you, there are two ways you can get around this.
If you are using the experimental public class fields syntax, you can use class fields to correctly bind callbacks:
class LoggingButton extends React.Component {
// This syntax ensures `this` is bound within handleClick.
// Warning: this is *experimental* syntax.
handleClick = () => { console.log('this is:', this); }
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
This syntax is enabled by default in Create React App.
If you aren't using class fields syntax, you can use an arrow function in the callback:
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// This syntax ensures `this` is bound within handleClick return ( <button onClick={() => this.handleClick()}> Click me
</button>
);
}
}
The problem with this syntax is that a different callback is created each time the LoggingButton
renders.
In most cases, this is fine.
However, if this callback is passed as a prop to lower components, those components might do an extra re-rendering.
We generally recommend binding in the constructor or using the class fields syntax, to avoid this sort of performance problem.
Passing Arguments to Event Handlers
Inside a loop, it is common to want to pass an extra parameter to an event handler.
For example, if id
is the row ID, either of the following would work:
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
The above two lines are equivalent, and use arrow functions and Function.prototype.bind
respectively.
In both cases, the e
argument representing the React event will be passed as a second argument after the ID.
With an arrow function, we have to pass it explicitly, but with bind
any further arguments are automatically forwarded.
Conditional Rendering
In React, you can create distinct components that encapsulate behavior you need.
Then, you can render only some of them, depending on the state of your application.
Conditional rendering in React works the same way conditions work in JavaScript.
Use JavaScript operators like if
or the conditional operator to create elements representing the current state, and let React update the UI to match them.
Consider these two components:
function UserGreeting(props) {
return <h2>Welcome back!</h2>;
}
function GuestGreeting(props) {
return <h2>Please sign up.</h2>;
}
We'll create a Greeting
component that displays either of these components depending on whether a user is logged in:
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) { return <UserGreeting />; } return <GuestGreeting />;}
ReactDOM.render(
// Try changing to isLoggedIn={true}:
<Greeting isLoggedIn={false} />, document.getElementById('root'));
Try it on CodePen
This example renders a different greeting depending on the value of isLoggedIn
prop.
Element Variables
You can use variables to store elements.
This can help you conditionally render a part of the component while the rest of the output doesn't change.
Consider these two new components representing Logout and Login buttons:
function LoginButton(props) {
return (
<button onClick={props.onClick}>
Login
</button>
);
}
function LogoutButton(props) {
return (
<button onClick={props.onClick}>
Logout
</button>
);
}
In the example below, we will create a stateful component called LoginControl
.
It will render either <LoginButton />
or <LogoutButton />
depending on its current state.
It will also render a <Greeting />
from the previous example:
class LoginControl extends React.Component {
constructor(props) {
super(props);
this.handleLoginClick = this.handleLoginClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
this.state = {isLoggedIn: false};
}
handleLoginClick() {
this.setState({isLoggedIn: true});
}
handleLogoutClick() {
this.setState({isLoggedIn: false});
}
render() {
const isLoggedIn = this.state.isLoggedIn;
let button;
if (isLoggedIn) { button = <LogoutButton onClick={this.handleLogoutClick} />; } else { button = <LoginButton onClick={this.handleLoginClick} />; }
return (
<div>
<Greeting isLoggedIn={isLoggedIn} /> {button} </div>
);
}
}
ReactDOM.render(
<LoginControl />,
document.getElementById('root')
);
Try it on CodePen
While declaring a variable and using an if
statement is a fine way to conditionally render a component, sometimes you might want to use a shorter syntax.
There are a few ways to inline conditions in JSX, explained below.
Inline If with Logical && Operator
You may embed expressions in JSX by wrapping them in curly braces.
This includes the JavaScript logical &&
operator.
It can be handy for conditionally including an element:
function Mailbox(props) {
const unreadMessages = props.unreadMessages;
return (
<div>
<h2>Hello!</h2>
{unreadMessages.length > 0 && <h3> You have {unreadMessages.length} unread messages.
</h3> } </div>
);
}
const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
<Mailbox unreadMessages={messages} />,
document.getElementById('root')
);
Try it on CodePen
It works because in JavaScript, true && expression
always evaluates to expression
, and false && expression
always evaluates to false
.
Therefore, if the condition is true
, the element right after &&
will appear in the output.
If it is false
, React will ignore and skip it.
Note that returning a falsy expression will still cause the element after &&
to be skipped but will return the falsy expression.
In the example below, <div>0</div>
will be returned by the render method.
render() {
const count = 0; return (
<div>
{ count && <h2>Messages: {count}</h2>} </div>
);
}
Inline If-Else with Conditional Operator
Another method for conditionally rendering elements inline is to use the JavaScript conditional operator condition ? true : false
.
In the example below, we use it to conditionally render a small block of text.
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
</div>
);
}
It can also be used for larger expressions although it is less obvious what's going on:
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
{isLoggedIn ? <LogoutButton onClick={this.handleLogoutClick} />
: <LoginButton onClick={this.handleLoginClick} /> }
</div> );
}
Just like in JavaScript, it is up to you to choose an appropriate style based on what you and your team consider more readable.
Also remember that whenever conditions become too complex, it might be a good time to extract a component.
Preventing Component from Rendering
In rare cases you might want a component to hide itself even though it was rendered by another component.
To do this return null
instead of its render output.
In the example below, the <WarningBanner />
is rendered depending on the value of the prop called warn
.
If the value of the prop is false
, then the component does not render:
function WarningBanner(props) {
if (!props.warn) { return null; }
return (
<div className="warning">
Warning!
</div>
);
}
class Page extends React.Component {
constructor(props) {
super(props);
this.state = {showWarning: true};
this.handleToggleClick = this.handleToggleClick.bind(this);
}
handleToggleClick() {
this.setState(state => ({
showWarning: !state.showWarning
}));
}
render() {
return (
<div>
<WarningBanner warn={this.state.showWarning} /> <button onClick={this.handleToggleClick}>
{this.state.showWarning ? 'Hide' : 'Show'}
</button>
</div>
);
}
}
ReactDOM.render(
<Page />,
document.getElementById('root')
);
Try it on CodePen
Returning null
from a component's render
method does not affect the firing of the component's lifecycle methods.
For instance componentDidUpdate
will still be called.
Lists and Keys
First, let's review how you transform lists in JavaScript.
Given the code below, we use the map()
function to take an array of numbers
and double their values.
We assign the new array returned by map()
to the variable doubled
and log it:
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2);console.log(doubled);
This code logs [2, 4, 6, 8, 10]
to the console.
In React, transforming arrays into lists of elements is nearly identical.
Rendering Multiple Components
You can build collections of elements and include them in JSX using curly braces {}
.
Below, we loop through the numbers
array using the JavaScript map()
function.
We return a <li>
element for each item.
Finally, we assign the resulting array of elements to listItems
:
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) => <li>{number}</li>);
We include the entire listItems
array inside a <ul>
element, and render it to the DOM:
ReactDOM.render(
<ul>{listItems}</ul>, document.getElementById('root')
);
Try it on CodePen
This code displays a bullet list of numbers between 1 and 5.
Basic List Component
Usually you would render lists inside a component.
We can refactor the previous example into a component that accepts an array of numbers
and outputs a list of elements.
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) => <li>{number}</li> ); return (
<ul>{listItems}</ul> );
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />, document.getElementById('root')
);
When you run this code, you'll be given a warning that a key should be provided for list items.
A ¡°key¡± is a special string attribute you need to include when creating lists of elements.
We'll discuss why it's important in the next section.
Let's assign a key
to our list items inside numbers.map()
and fix the missing key issue.
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.toString()}> {number}
</li>
);
return (
<ul>{listItems}</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
Try it on CodePen
Keys
Keys help React identify which items have changed, are added, or are removed.
Keys should be given to the elements inside the array to give the elements a stable identity:
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li key={number.toString()}> {number}
</li>
);
The best way to pick a key is to use a string that uniquely identifies a list item among its siblings.
Most often you would use IDs from your data as keys:
const todoItems = todos.map((todo) =>
<li key={todo.id}> {todo.text}
</li>
);
When you don't have stable IDs for rendered items, you may use the item index as a key as a last resort:
const todoItems = todos.map((todo, index) =>
// Only do this if items have no stable IDs <li key={index}> {todo.text}
</li>
);
We don't recommend using indexes for keys if the order of items may change.
This can negatively impact performance and may cause issues with component state.
Check out Robin Pokorny's article for an in-depth explanation on the negative impacts of using an index as a key.
If you choose not to assign an explicit key to list items then React will default to using indexes as keys.
Here is an in-depth explanation about why keys are necessary if you're interested in learning more.
Extracting Components with Keys
Keys only make sense in the context of the surrounding array.
For example, if you extract a ListItem
component, you should keep the key on the <ListItem />
elements in the array rather than on the <li>
element in the ListItem
itself.
Example: Incorrect Key Usage
function ListItem(props) {
const value = props.value;
return (
// Wrong! There is no need to specify the key here: <li key={value.toString()}> {value}
</li>
);
}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// Wrong! The key should have been specified here: <ListItem value={number} /> );
return (
<ul>
{listItems}
</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
Example: Correct Key Usage
function ListItem(props) {
// Correct! There is no need to specify the key here: return <li>{props.value}</li>;}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// Correct! Key should be specified inside the array.
<ListItem key={number.toString()} value={number} /> );
return (
<ul>
{listItems}
</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
Try it on CodePen
A good rule of thumb is that elements inside the map()
call need keys.
Keys Must Only Be Unique Among Siblings
Keys used within arrays should be unique among their siblings.
However they don't need to be globally unique.
We can use the same keys when we produce two different arrays:
function Blog(props) {
const sidebar = ( <ul>
{props.posts.map((post) =>
<li key={post.id}> {post.title}
</li>
)}
</ul>
);
const content = props.posts.map((post) => <div key={post.id}> <h4>{post.title}</h4>
<p>{post.content}</p>
</div>
);
return (
<div>
{sidebar} <hr />
{content} </div>
);
}
const posts = [
{id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
{id: 2, title: 'Installation', content: 'You can install React from npm.'}
];
ReactDOM.render(
<Blog posts={posts} />,
document.getElementById('root')
);
Try it on CodePen
Keys serve as a hint to React but they don't get passed to your components.
If you need the same value in your component, pass it explicitly as a prop with a different name:
const content = posts.map((post) =>
<Post
key={post.id} id={post.id} title={post.title} />
);
With the example above, the Post
component can read props.id
, but not props.key
.
Embedding map() in JSX
In the examples above we declared a separate listItems
variable and included it in JSX:
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) => <ListItem key={number.toString()} value={number} /> ); return (
<ul>
{listItems}
</ul>
);
}
JSX allows embedding any expression in curly braces so we could inline the map()
result:
function NumberList(props) {
const numbers = props.numbers;
return (
<ul>
{numbers.map((number) => <ListItem key={number.toString()} value={number} /> )} </ul>
);
}
Try it on CodePen
Sometimes this results in clearer code, but this style can also be abused.
Like in JavaScript, it is up to you to decide whether it is worth extracting a variable for readability.
Keep in mind that if the map()
body is too nested, it might be a good time to extract a component.
Forms
HTML form elements work a little bit differently from other DOM elements in React, because form elements naturally keep some internal state.
For example, this form in plain HTML accepts a single name:
<form>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit" value="Submit" />
</form>
This form has the default HTML form behavior of browsing to a new page when the user submits the form.
If you want this behavior in React, it just works.
But in most cases, it's convenient to have a JavaScript function that handles the submission of the form and has access to the data that the user entered into the form.
The standard way to achieve this is with a technique called ¡°controlled components¡±.
Controlled Components
In HTML, form elements such as <input>
, <textarea>
, and <select>
typically maintain their own state and update it based on user input.
In React, mutable state is typically kept in the state property of components, and only updated with setState()
.
We can combine the two by making the React state be the ¡°single source of truth¡±.
Then the React component that renders a form also controls what happens in that form on subsequent user input.
An input form element whose value is controlled by React in this way is called a ¡°controlled component¡±.
For example, if we want to make the previous example log the name when it is submitted, we can write the form as a controlled component:
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) { this.setState({value: event.target.value}); }
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}> <label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} /> </label>
<input type="submit" value="Submit" />
</form>
);
}
}
Try it on CodePen
Since the value
attribute is set on our form element, the displayed value will always be this.state.value
, making the React state the source of truth.
Since handleChange
runs on every keystroke to update the React state, the displayed value will update as the user types.
With a controlled component, the input's value is always driven by the React state.
While this means you have to type a bit more code, you can now pass the value to other UI elements too, or reset it from other event handlers.
The textarea Tag
In HTML, a <textarea>
element defines its text by its children:
<textarea>
Hello there, this is some text in a text area
</textarea>
In React, a <textarea>
uses a value
attribute instead.
This way, a form using a <textarea>
can be written very similarly to a form that uses a single-line input:
class EssayForm extends React.Component {
constructor(props) {
super(props);
this.state = { value: 'Please write an essay about your favorite DOM element.' };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) { this.setState({value: event.target.value}); }
handleSubmit(event) {
alert('An essay was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Essay:
<textarea value={this.state.value} onChange={this.handleChange} /> </label>
<input type="submit" value="Submit" />
</form>
);
}
}
Notice that this.state.value
is initialized in the constructor, so that the text area starts off with some text in it.
The select Tag
In HTML, <select>
creates a drop-down list.
For example, this HTML creates a drop-down list of flavors:
<select>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option selected value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
Note that the Coconut option is initially selected, because of the selected
attribute.
React, instead of using this selected
attribute, uses a value
attribute on the root select
tag.
This is more convenient in a controlled component because you only need to update it in one place.
For example:
class FlavorForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: 'coconut'};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) { this.setState({value: event.target.value}); }
handleSubmit(event) {
alert('Your favorite flavor is: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Pick your favorite flavor:
<select value={this.state.value} onChange={this.handleChange}> <option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Try it on CodePen
Overall, this makes it so that <input type="text">
, <textarea>
, and <select>
all work very similarly - they all accept a value
attribute that you can use to implement a controlled component.
Note
You can pass an array into the value
attribute, allowing you to select multiple options in a select
tag:
<select multiple={true} value={['B', 'C']}>
The file input Tag
In HTML, an <input type="file">
lets the user choose one or more files from their device storage to be uploaded to a server or manipulated by JavaScript via the File API.
<input type="file" />
Because its value is read-only, it is an uncontrolled component in React.
It is discussed together with other uncontrolled components later in the documentation.
Handling Multiple Inputs
When you need to handle multiple controlled input
elements, you can add a name
attribute to each element and let the handler function choose what to do based on the value of event.target.name
.
For example:
class Reservation extends React.Component {
constructor(props) {
super(props);
this.state = {
isGoing: true,
numberOfGuests: 2
};
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value });
}
render() {
return (
<form>
<label>
Is going:
<input
name="isGoing" type="checkbox"
checked={this.state.isGoing}
onChange={this.handleInputChange} />
</label>
<br />
<label>
Number of guests:
<input
name="numberOfGuests" type="number"
value={this.state.numberOfGuests}
onChange={this.handleInputChange} />
</label>
</form>
);
}
}
Try it on CodePen
Note how we used the ES6 computed property name syntax to update the state key corresponding to the given input name:
this.setState({
[name]: value});
It is equivalent to this ES5 code:
var partialState = {};
partialState[name] = value;this.setState(partialState);
Also, since setState()
automatically merges a partial state into the current state, we only needed to call it with the changed parts.
Controlled Input Null Value
Specifying the value prop on a controlled component prevents the user from changing the input unless you desire so.
If you've specified a value
but the input is still editable, you may have accidentally set value
to undefined
or null
.
The following code demonstrates this.
(The input is locked at first but becomes editable after a short delay.)
ReactDOM.render(<input value="hi" />, mountNode);
setTimeout(function() {
ReactDOM.render(<input value={null} />, mountNode);
}, 1000);
Alternatives to Controlled Components
It can sometimes be tedious to use controlled components, because you need to write an event handler for every way your data can change and pipe all of the input state through a React component.
This can become particularly annoying when you are converting a preexisting codebase to React, or integrating a React application with a non-React library.
In these situations, you might want to check out uncontrolled components, an alternative technique for implementing input forms.
Fully-Fledged Solutions
If you're looking for a complete solution including validation, keeping track of the visited fields, and handling form submission, Formik is one of the popular choices.
However, it is built on the same principles of controlled components and managing state ¡ª so don't neglect to learn them.
Lifting State Up
Often, several components need to reflect the same changing data.
We recommend lifting the shared state up to their closest common ancestor.
Let's see how this works in action.
In this section, we will create a temperature calculator that calculates whether the water would boil at a given temperature.
We will start with a component called BoilingVerdict
.
It accepts the celsius
temperature as a prop, and prints whether it is enough to boil the water:
function BoilingVerdict(props) {
if (props.celsius >= 100) {
return <p>The water would boil.</p>; }
return <p>The water would not boil.</p>;}
Next, we will create a component called Calculator
.
It renders an <input>
that lets you enter the temperature, and keeps its value in this.state.temperature
.
Additionally, it renders the BoilingVerdict
for the current input value.
class Calculator extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {temperature: ''}; }
handleChange(e) {
this.setState({temperature: e.target.value}); }
render() {
const temperature = this.state.temperature; return (
<fieldset>
<legend>Enter temperature in Celsius:</legend>
<input value={temperature} onChange={this.handleChange} /> <BoilingVerdict celsius={parseFloat(temperature)} /> </fieldset>
);
}
}
Try it on CodePen
Adding a Second Input
Our new requirement is that, in addition to a Celsius input, we provide a Fahrenheit input, and they are kept in sync.
We can start by extracting a TemperatureInput
component from Calculator
.
We will add a new scale
prop to it that can either be "c"
or "f"
:
const scaleNames = { c: 'Celsius', f: 'Fahrenheit'};
class TemperatureInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {temperature: ''};
}
handleChange(e) {
this.setState({temperature: e.target.value});
}
render() {
const temperature = this.state.temperature;
const scale = this.props.scale; return (
<fieldset>
<legend>Enter temperature in {scaleNames[scale]}:</legend> <input value={temperature}
onChange={this.handleChange} />
</fieldset>
);
}
}
We can now change the Calculator
to render two separate temperature inputs:
class Calculator extends React.Component {
render() {
return (
<div>
<TemperatureInput scale="c" /> <TemperatureInput scale="f" /> </div>
);
}
}
Try it on CodePen
We have two inputs now, but when you enter the temperature in one of them, the other doesn't update.
This contradicts our requirement: we want to keep them in sync.
We also can't display the BoilingVerdict
from Calculator
.
The Calculator
doesn't know the current temperature because it is hidden inside the TemperatureInput
.
Writing Conversion Functions
First, we will write two functions to convert from Celsius to Fahrenheit and back:
function toCelsius(fahrenheit) {
return (fahrenheit - 32) * 5 / 9;
}
function toFahrenheit(celsius) {
return (celsius * 9 / 5) + 32;
}
These two functions convert numbers.
We will write another function that takes a string temperature
and a converter function as arguments and returns a string.
We will use it to calculate the value of one input based on the other input.
It returns an empty string on an invalid temperature
, and it keeps the output rounded to the third decimal place:
function tryConvert(temperature, convert) {
const input = parseFloat(temperature);
if (Number.isNaN(input)) {
return '';
}
const output = convert(input);
const rounded = Math.round(output * 1000) / 1000;
return rounded.toString();
}
For example, tryConvert('abc', toCelsius)
returns an empty string, and tryConvert('10.22', toFahrenheit)
returns '50.396'
.
Lifting State Up
Currently, both TemperatureInput
components independently keep their values in the local state:
class TemperatureInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {temperature: ''}; }
handleChange(e) {
this.setState({temperature: e.target.value}); }
render() {
const temperature = this.state.temperature; // ...
However, we want these two inputs to be in sync with each other.
When we update the Celsius input, the Fahrenheit input should reflect the converted temperature, and vice versa.
In React, sharing state is accomplished by moving it up to the closest common ancestor of the components that need it.
This is called ¡°lifting state up¡±.
We will remove the local state from the TemperatureInput
and move it into the Calculator
instead.
If the Calculator
owns the shared state, it becomes the ¡°source of truth¡± for the current temperature in both inputs.
It can instruct them both to have values that are consistent with each other.
Since the props of both TemperatureInput
components are coming from the same parent Calculator
component, the two inputs will always be in sync.
Let's see how this works step by step.
First, we will replace this.state.temperature
with this.props.temperature
in the TemperatureInput
component.
For now, let's pretend this.props.temperature
already exists, although we will need to pass it from the Calculator
in the future:
render() {
// Before: const temperature = this.state.temperature;
const temperature = this.props.temperature; // ...
We know that props are read-only.
When the temperature
was in the local state, the TemperatureInput
could just call this.setState()
to change it.
However, now that the temperature
is coming from the parent as a prop, the TemperatureInput
has no control over it.
In React, this is usually solved by making a component ¡°controlled¡±.
Just like the DOM <input>
accepts both a value
and an onChange
prop, so can the custom TemperatureInput
accept both temperature
and onTemperatureChange
props from its parent Calculator
.
Now, when the TemperatureInput
wants to update its temperature, it calls this.props.onTemperatureChange
:
handleChange(e) {
// Before: this.setState({temperature: e.target.value});
this.props.onTemperatureChange(e.target.value); // ...
Note:
There is no special meaning to either temperature
or onTemperatureChange
prop names in custom components.
We could have called them anything else, like name them value
and onChange
which is a common convention.
The onTemperatureChange
prop will be provided together with the temperature
prop by the parent Calculator
component.
It will handle the change by modifying its own local state, thus re-rendering both inputs with the new values.
We will look at the new Calculator
implementation very soon.
Before diving into the changes in the Calculator
, let's recap our changes to the TemperatureInput
component.
We have removed the local state from it, and instead of reading this.state.temperature
, we now read this.props.temperature
.
Instead of calling this.setState()
when we want to make a change, we now call this.props.onTemperatureChange()
, which will be provided by the Calculator
:
class TemperatureInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.props.onTemperatureChange(e.target.value); }
render() {
const temperature = this.props.temperature; const scale = this.props.scale;
return (
<fieldset>
<legend>Enter temperature in {scaleNames[scale]}:</legend>
<input value={temperature}
onChange={this.handleChange} />
</fieldset>
);
}
}
Now let's turn to the Calculator
component.
We will store the current input's temperature
and scale
in its local state.
This is the state we ¡°lifted up¡± from the inputs, and it will serve as the ¡°source of truth¡± for both of them.
It is the minimal representation of all the data we need to know in order to render both inputs.
For example, if we enter 37 into the Celsius input, the state of the Calculator
component will be:
{
temperature: '37',
scale: 'c'
}
If we later edit the Fahrenheit field to be 212, the state of the Calculator
will be:
{
temperature: '212',
scale: 'f'
}
We could have stored the value of both inputs but it turns out to be unnecessary.
It is enough to store the value of the most recently changed input, and the scale that it represents.
We can then infer the value of the other input based on the current temperature
and scale
alone.
The inputs stay in sync because their values are computed from the same state:
class Calculator extends React.Component {
constructor(props) {
super(props);
this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
this.state = {temperature: '', scale: 'c'}; }
handleCelsiusChange(temperature) {
this.setState({scale: 'c', temperature}); }
handleFahrenheitChange(temperature) {
this.setState({scale: 'f', temperature}); }
render() {
const scale = this.state.scale; const temperature = this.state.temperature; const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature; const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;
return (
<div>
<TemperatureInput
scale="c"
temperature={celsius} onTemperatureChange={this.handleCelsiusChange} /> <TemperatureInput
scale="f"
temperature={fahrenheit} onTemperatureChange={this.handleFahrenheitChange} /> <BoilingVerdict
celsius={parseFloat(celsius)} /> </div>
);
}
}
Try it on CodePen
Now, no matter which input you edit, this.state.temperature
and this.state.scale
in the Calculator
get updated.
One of the inputs gets the value as is, so any user input is preserved, and the other input value is always recalculated based on it.
Let's recap what happens when you edit an input:
- React calls the function specified as
onChange
on the DOM <input>
.
In our case, this is the handleChange
method in the TemperatureInput
component.
- The
handleChange
method in the TemperatureInput
component calls this.props.onTemperatureChange()
with the new desired value.
Its props, including onTemperatureChange
, were provided by its parent component, the Calculator
.
- When it previously rendered, the
Calculator
had specified that onTemperatureChange
of the Celsius TemperatureInput
is the Calculator
's handleCelsiusChange
method, and onTemperatureChange
of the Fahrenheit TemperatureInput
is the Calculator
's handleFahrenheitChange
method.
So either of these two Calculator
methods gets called depending on which input we edited.
- Inside these methods, the
Calculator
component asks React to re-render itself by calling this.setState()
with the new input value and the current scale of the input we just edited.
- React calls the
Calculator
component's render
method to learn what the UI should look like.
The values of both inputs are recomputed based on the current temperature and the active scale.
The temperature conversion is performed here.
- React calls the
render
methods of the individual TemperatureInput
components with their new props specified by the Calculator
.
It learns what their UI should look like.
- React calls the
render
method of the BoilingVerdict
component, passing the temperature in Celsius as its props.
- React DOM updates the DOM with the boiling verdict and to match the desired input values.
The input we just edited receives its current value, and the other input is updated to the temperature after conversion.
Every update goes through the same steps so the inputs stay in sync.
Lessons Learned
There should be a single ¡°source of truth¡± for any data that changes in a React application.
Usually, the state is first added to the component that needs it for rendering.
Then, if other components also need it, you can lift it up to their closest common ancestor.
Instead of trying to sync the state between different components, you should rely on the top-down data flow.
Lifting state involves writing more ¡°boilerplate¡± code than two-way binding approaches, but as a benefit, it takes less work to find and isolate bugs.
Since any state ¡°lives¡± in some component and that component alone can change it, the surface area for bugs is greatly reduced.
Additionally, you can implement any custom logic to reject or transform user input.
If something can be derived from either props or state, it probably shouldn't be in the state.
For example, instead of storing both celsiusValue
and fahrenheitValue
, we store just the last edited temperature
and its scale
.
The value of the other input can always be calculated from them in the render()
method.
This lets us clear or apply rounding to the other field without losing any precision in the user input.
When you see something wrong in the UI, you can use React Developer Tools to inspect the props and move up the tree until you find the component responsible for updating the state.
This lets you trace the bugs to their source:
Composition vs Inheritance
React has a powerful composition model, and we recommend using composition instead of inheritance to reuse code between components.
In this section, we will consider a few problems where developers new to React often reach for inheritance, and show how we can solve them with composition.
Containment
Some components don't know their children ahead of time.
This is especially common for components like Sidebar
or Dialog
that represent generic ¡°boxes¡±.
We recommend that such components use the special children
prop to pass children elements directly into their output:
function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children} </div>
);
}
This lets other components pass arbitrary children to them by nesting the JSX:
function WelcomeDialog() {
return (
<FancyBorder color="blue">
<h2 className="Dialog-title"> Welcome </h2> <p className="Dialog-message"> Thank you for visiting our spacecraft! </p> </FancyBorder>
);
}
Try it on CodePen
Anything inside the <FancyBorder>
JSX tag gets passed into the FancyBorder
component as a children
prop.
Since FancyBorder
renders {props.children}
inside a <div>
, the passed elements appear in the final output.
While this is less common, sometimes you might need multiple ¡°holes¡± in a component.
In such cases you may come up with your own convention instead of using children
:
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left} </div>
<div className="SplitPane-right">
{props.right} </div>
</div>
);
}
function App() {
return (
<SplitPane
left={
<Contacts /> }
right={
<Chat /> } />
);
}
Try it on CodePen
React elements like <Contacts />
and <Chat />
are just objects, so you can pass them as props like any other data.
This approach may remind you of ¡°slots¡± in other libraries but there are no limitations on what you can pass as props in React.
Specialization
Sometimes we think about components as being ¡°special cases¡± of other components.
For example, we might say that a WelcomeDialog
is a special case of Dialog
.
In React, this is also achieved by composition, where a more ¡°specific¡± component renders a more ¡°generic¡± one and configures it with props:
function Dialog(props) {
return (
<FancyBorder color="blue">
<h2 className="Dialog-title">
{props.title} </h2>
<p className="Dialog-message">
{props.message} </p>
</FancyBorder>
);
}
function WelcomeDialog() {
return (
<Dialog title="Welcome" message="Thank you for visiting our spacecraft!" /> );
}
Try it on CodePen
Composition works equally well for components defined as classes:
function Dialog(props) {
return (
<FancyBorder color="blue">
<h2 className="Dialog-title">
{props.title}
</h2>
<p className="Dialog-message">
{props.message}
</p>
{props.children} </FancyBorder>
);
}
class SignUpDialog extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleSignUp = this.handleSignUp.bind(this);
this.state = {login: ''};
}
render() {
return (
<Dialog title="Mars Exploration Program"
message="How should we refer to you?">
<input value={this.state.login} onChange={this.handleChange} /> <button onClick={this.handleSignUp}> Sign Me Up! </button> </Dialog>
);
}
handleChange(e) {
this.setState({login: e.target.value});
}
handleSignUp() {
alert(`Welcome aboard, ${this.state.login}!`);
}
}
Try it on CodePen
So What About Inheritance?
At Facebook, we use React in thousands of components, and we haven't found any use cases where we would recommend creating component inheritance hierarchies.
Props and composition give you all the flexibility you need to customize a component's look and behavior in an explicit and safe way.
Remember that components may accept arbitrary props, including primitive values, React elements, or functions.
If you want to reuse non-UI functionality between components, we suggest extracting it into a separate JavaScript module.
The components may import it and use that function, object, or a class, without extending it.
Thinking in React
React is, in our opinion, the premier way to build big, fast Web apps with JavaScript.
It has scaled very well for us at Facebook and Instagram.
One of the many great parts of React is how it makes you think about apps as you build them.
In this document, we'll walk you through the thought process of building a searchable product data table using React.
Start With A Mock
Imagine that we already have a JSON API and a mock from our designer.
The mock looks like this:
Our JSON API returns some data that looks like this:
[
{category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},
{category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},
{category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},
{category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},
{category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},
{category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}
];
Step 1: Break The UI Into A Component Hierarchy
The first thing you'll want to do is to draw boxes around every component (and subcomponent) in the mock and give them all names.
If you're working with a designer, they may have already done this, so go talk to them! Their Photoshop layer names may end up being the names of your React components!
But how do you know what should be its own component? Use the same techniques for deciding if you should create a new function or object.
One such technique is the single responsibility principle, that is, a component should ideally only do one thing.
If it ends up growing, it should be decomposed into smaller subcomponents.
Since you're often displaying a JSON data model to a user, you'll find that if your model was built correctly, your UI (and therefore your component structure) will map nicely.
That's because UI and data models tend to adhere to the same information architecture.
Separate your UI into components, where each component matches one piece of your data model.
You'll see here that we have five components in our app.
We've italicized the data each component represents.
-
FilterableProductTable
(orange): contains the entirety of the example
-
SearchBar
(blue): receives all user input
-
ProductTable
(green): displays and filters the data collection based on user input
-
ProductCategoryRow
(turquoise): displays a heading for each category
-
ProductRow
(red): displays a row for each product
If you look at ProductTable
, you'll see that the table header (containing the ¡°Name¡± and ¡°Price¡± labels) isn't its own component.
This is a matter of preference, and there's an argument to be made either way.
For this example, we left it as part of ProductTable
because it is part of rendering the data collection which is ProductTable
's responsibility.
However, if this header grows to be complex (e.g., if we were to add affordances for sorting), it would certainly make sense to make this its own ProductTableHeader
component.
Now that we've identified the components in our mock, let's arrange them into a hierarchy.
Components that appear within another component in the mock should appear as a child in the hierarchy:
-
FilterableProductTable
SearchBar
-
ProductTable
ProductCategoryRow
ProductRow
Step 2: Build A Static Version in React
See the Pen Thinking In React: Step 2 on CodePen.
Now that you have your component hierarchy, it's time to implement your app.
The easiest way is to build a version that takes your data model and renders the UI but has no interactivity.
It's best to decouple these processes because building a static version requires a lot of typing and no thinking, and adding interactivity requires a lot of thinking and not a lot of typing.
We'll see why.
To build a static version of your app that renders your data model, you'll want to build components that reuse other components and pass data using props.
props are a way of passing data from parent to child.
If you're familiar with the concept of state, don't use state at all to build this static version.
State is reserved only for interactivity, that is, data that changes over time.
Since this is a static version of the app, you don't need it.
You can build top-down or bottom-up.
That is, you can either start with building the components higher up in the hierarchy (i.e.
starting with FilterableProductTable
) or with the ones lower in it (ProductRow
).
In simpler examples, it's usually easier to go top-down, and on larger projects, it's easier to go bottom-up and write tests as you build.
At the end of this step, you'll have a library of reusable components that render your data model.
The components will only have render()
methods since this is a static version of your app.
The component at the top of the hierarchy (FilterableProductTable
) will take your data model as a prop.
If you make a change to your underlying data model and call ReactDOM.render()
again, the UI will be updated.
You can see how your UI is updated and where to make changes.
React's one-way data flow (also called one-way binding) keeps everything modular and fast.
Refer to the React docs if you need help executing this step.
A Brief Interlude: Props vs State
There are two types of ¡°model¡± data in React: props and state.
It's important to understand the distinction between the two; skim the official React docs if you aren't sure what the difference is.
See also FAQ: What is the difference between state and props?
Step 3: Identify The Minimal (but complete) Representation Of UI State
To make your UI interactive, you need to be able to trigger changes to your underlying data model.
React achieves this with state.
To build your app correctly, you first need to think of the minimal set of mutable state that your app needs.
The key here is DRY: Don't Repeat Yourself.
Figure out the absolute minimal representation of the state your application needs and compute everything else you need on-demand.
For example, if you're building a TODO list, keep an array of the TODO items around; don't keep a separate state variable for the count.
Instead, when you want to render the TODO count, take the length of the TODO items array.
Think of all of the pieces of data in our example application.
We have:
- The original list of products
- The search text the user has entered
- The value of the checkbox
- The filtered list of products
Let's go through each one and figure out which one is state.
Ask three questions about each piece of data:
- Is it passed in from a parent via props? If so, it probably isn't state.
- Does it remain unchanged over time? If so, it probably isn't state.
- Can you compute it based on any other state or props in your component? If so, it isn't state.
The original list of products is passed in as props, so that's not state.
The search text and the checkbox seem to be state since they change over time and can't be computed from anything.
And finally, the filtered list of products isn't state because it can be computed by combining the original list of products with the search text and value of the checkbox.
So finally, our state is:
- The search text the user has entered
- The value of the checkbox
Step 4: Identify Where Your State Should Live
See the Pen Thinking In React: Step 4 on CodePen.
OK, so we've identified what the minimal set of app state is.
Next, we need to identify which component mutates, or owns, this state.
Remember: React is all about one-way data flow down the component hierarchy.
It may not be immediately clear which component should own what state.
This is often the most challenging part for newcomers to understand, so follow these steps to figure it out:
For each piece of state in your application:
- Identify every component that renders something based on that state.
- Find a common owner component (a single component above all the components that need the state in the hierarchy).
- Either the common owner or another component higher up in the hierarchy should own the state.
- If you can't find a component where it makes sense to own the state, create a new component solely for holding the state and add it somewhere in the hierarchy above the common owner component.
Let's run through this strategy for our application:
-
ProductTable
needs to filter the product list based on state and SearchBar
needs to display the search text and checked state.
- The common owner component is
FilterableProductTable
.
- It conceptually makes sense for the filter text and checked value to live in
FilterableProductTable
Cool, so we've decided that our state lives in FilterableProductTable
.
First, add an instance property this.state = {filterText: '', inStockOnly: false}
to FilterableProductTable
's constructor
to reflect the initial state of your application.
Then, pass filterText
and inStockOnly
to ProductTable
and SearchBar
as a prop.
Finally, use these props to filter the rows in ProductTable
and set the values of the form fields in SearchBar
.
You can start seeing how your application will behave: set filterText
to "ball"
and refresh your app.
You'll see that the data table is updated correctly.
Step 5: Add Inverse Data Flow
See the Pen Thinking In React: Step 5 on CodePen.
So far, we've built an app that renders correctly as a function of props and state flowing down the hierarchy.
Now it's time to support data flowing the other way: the form components deep in the hierarchy need to update the state in FilterableProductTable
.
React makes this data flow explicit to help you understand how your program works, but it does require a little more typing than traditional two-way data binding.
If you try to type or check the box in the current version of the example, you'll see that React ignores your input.
This is intentional, as we've set the value
prop of the input
to always be equal to the state
passed in from FilterableProductTable
.
Let's think about what we want to happen.
We want to make sure that whenever the user changes the form, we update the state to reflect the user input.
Since components should only update their own state, FilterableProductTable
will pass callbacks to SearchBar
that will fire whenever the state should be updated.
We can use the onChange
event on the inputs to be notified of it.
The callbacks passed by FilterableProductTable
will call setState()
, and the app will be updated.
And That's It
Hopefully, this gives you an idea of how to think about building components and applications with React.
While it may be a little more typing than you're used to, remember that code is read far more than it's written, and it's less difficult to read this modular, explicit code.
As you start to build large libraries of components, you'll appreciate this explicitness and modularity, and with code reuse, your lines of code will start to shrink.
:)
Accessibility
Why Accessibility?
Web accessibility (also referred to as a11y) is the design and creation of websites that can be used by everyone.
Accessibility support is necessary to allow assistive technology to interpret web pages.
React fully supports building accessible websites, often by using standard HTML techniques.
Standards and Guidelines
WCAG
The Web Content Accessibility Guidelines provides guidelines for creating accessible web sites.
The following WCAG checklists provide an overview:
- WCAG checklist from Wuhcag
- WCAG checklist from WebAIM
- Checklist from The A11Y Project
WAI-ARIA
The Web Accessibility Initiative - Accessible Rich Internet Applications document contains techniques for building fully accessible JavaScript widgets.
Note that all aria-*
HTML attributes are fully supported in JSX.
Whereas most DOM properties and attributes in React are camelCased, these attributes should be hyphen-cased (also known as kebab-case, lisp-case, etc) as they are in plain HTML:
<input
type="text"
aria-label={labelText} aria-required="true" onChange={onchangeHandler}
value={inputValue}
name="name"
/>
Semantic HTML
Semantic HTML is the foundation of accessibility in a web application.
Using the various HTML elements to reinforce the meaning of information
in our websites will often give us accessibility for free.
- MDN HTML elements reference
Sometimes we break HTML semantics when we add <div>
elements to our JSX to make our React code work, especially when working with lists (<ol>
, <ul>
and <dl>
) and the HTML <table>
.
In these cases we should rather use React Fragments to group together multiple elements.
For example,
import React, { Fragment } from 'react';
function ListItem({ item }) {
return (
<Fragment> <dt>{item.term}</dt>
<dd>{item.description}</dd>
</Fragment> );
}
function Glossary(props) {
return (
<dl>
{props.items.map(item => (
<ListItem item={item} key={item.id} />
))}
</dl>
);
}
You can map a collection of items to an array of fragments as you would any other type of element as well:
function Glossary(props) {
return (
<dl>
{props.items.map(item => (
// Fragments should also have a `key` prop when mapping collections
<Fragment key={item.id}> <dt>{item.term}</dt>
<dd>{item.description}</dd>
</Fragment> ))}
</dl>
);
}
When you don't need any props on the Fragment tag you can use the short syntax, if your tooling supports it:
function ListItem({ item }) {
return (
<> <dt>{item.term}</dt>
<dd>{item.description}</dd>
</> );
}
For more info, see the Fragments documentation.
Accessible Forms
Labeling
Every HTML form control, such as <input>
and <textarea>
, needs to be labeled accessibly.
We need to provide descriptive labels that are also exposed to screen readers.
The following resources show us how to do this:
- The W3C shows us how to label elements
- WebAIM shows us how to label elements
- The Paciello Group explains accessible names
Although these standard HTML practices can be directly used in React, note that the for
attribute is written as htmlFor
in JSX:
<label htmlFor="namedInput">Name:</label><input>
Notifying the user of errors
Error situations need to be understood by all users.
The following link shows us how to expose error texts to screen readers as well:
- The W3C demonstrates user notifications
- WebAIM looks at form validation
Focus Control
Ensure that your web application can be fully operated with the keyboard only:
- WebAIM talks about keyboard accessibility
Keyboard focus and focus outline
Keyboard focus refers to the current element in the DOM that is selected to accept input from the keyboard.
We see it everywhere as a focus outline similar to that shown in the following image:
Only ever use CSS that removes this outline, for example by setting outline: 0
, if you are replacing it with another focus outline implementation.
Mechanisms to skip to desired content
Provide a mechanism to allow users to skip past navigation sections in your application as this assists and speeds up keyboard navigation.
Skiplinks or Skip Navigation Links are hidden navigation links that only become visible when keyboard users interact with the page.
They are very easy to implement with internal page anchors and some styling:
- WebAIM - Skip Navigation Links
Also use landmark elements and roles, such as <main>
and <aside>
, to demarcate page regions as assistive technology allow the user to quickly navigate to these sections.
Read more about the use of these elements to enhance accessibility here:
Programmatically managing focus
Our React applications continuously modify the HTML DOM during runtime, sometimes leading to keyboard focus being lost or set to an unexpected element.
In order to repair this, we need to programmatically nudge the keyboard focus in the right direction.
For example, by resetting keyboard focus to a button that opened a modal window after that modal window is closed.
MDN Web Docs takes a look at this and describes how we can build keyboard-navigable JavaScript widgets.
To set focus in React, we can use Refs to DOM elements.
Using this, we first create a ref to an element in the JSX of a component class:
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
// Create a ref to store the textInput DOM element this.textInput = React.createRef(); }
render() {
// Use the `ref` callback to store a reference to the text input DOM // element in an instance field (for example, this.textInput).
return (
<input
type="text"
ref={this.textInput} />
);
}
}
Then we can focus it elsewhere in our component when needed:
focus() {
// Explicitly focus the text input using the raw DOM API
// Note: we're accessing "current" to get the DOM node
this.textInput.current.focus();
}
Sometimes a parent component needs to set focus to an element in a child component.
We can do this by exposing DOM refs to parent components through a special prop on the child component that forwards the parent's ref to the child's DOM node.
function CustomTextInput(props) {
return (
<div>
<input ref={props.inputRef} /> </div>
);
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.inputElement = React.createRef(); }
render() {
return (
<CustomTextInput inputRef={this.inputElement} /> );
}
}
// Now you can set focus when required.
this.inputElement.current.focus();
When using a HOC to extend components, it is recommended to forward the ref to the wrapped component using the forwardRef
function of React.
If a third party HOC does not implement ref forwarding, the above pattern can still be used as a fallback.
A great focus management example is the react-aria-modal.
This is a relatively rare example of a fully accessible modal window.
Not only does it set initial focus on
the cancel button (preventing the keyboard user from accidentally activating the success action) and trap keyboard focus inside the modal, it also resets focus back to the element that initially triggered the modal.
Note:
While this is a very important accessibility feature, it is also a technique that should be used judiciously.
Use it to repair the keyboard focus flow when it is disturbed, not to try and anticipate how
users want to use applications.
Mouse and pointer events
Ensure that all functionality exposed through a mouse or pointer event can also be accessed using the keyboard alone.
Depending only on the pointer device will lead to many cases where keyboard users cannot use your application.
To illustrate this, let's look at a prolific example of broken accessibility caused by click events.
This is the outside click pattern, where a user can disable an opened popover by clicking outside the element.
This is typically implemented by attaching a click
event to the window
object that closes the popover:
class OuterClickExample extends React.Component {
constructor(props) {
super(props);
this.state = { isOpen: false };
this.toggleContainer = React.createRef();
this.onClickHandler = this.onClickHandler.bind(this);
this.onClickOutsideHandler = this.onClickOutsideHandler.bind(this);
}
componentDidMount() { window.addEventListener('click', this.onClickOutsideHandler); }
componentWillUnmount() {
window.removeEventListener('click', this.onClickOutsideHandler);
}
onClickHandler() {
this.setState(currentState => ({
isOpen: !currentState.isOpen
}));
}
onClickOutsideHandler(event) { if (this.state.isOpen && !this.toggleContainer.current.contains(event.target)) { this.setState({ isOpen: false }); } }
render() {
return (
<div ref={this.toggleContainer}>
<button onClick={this.onClickHandler}>Select an option</button>
{this.state.isOpen && (
<ul>
<li>Option 1</li>
<li>Option 2</li>
<li>Option 3</li>
</ul>
)}
</div>
);
}
}
This may work fine for users with pointer devices, such as a mouse, but operating this with the keyboard alone leads to broken functionality when tabbing to the next element as the window
object never receives a click
event.
This can lead to obscured functionality which blocks users from using your application.
The same functionality can be achieved by using appropriate event handlers instead, such as onBlur
and onFocus
:
class BlurExample extends React.Component {
constructor(props) {
super(props);
this.state = { isOpen: false };
this.timeOutId = null;
this.onClickHandler = this.onClickHandler.bind(this);
this.onBlurHandler = this.onBlurHandler.bind(this);
this.onFocusHandler = this.onFocusHandler.bind(this);
}
onClickHandler() {
this.setState(currentState => ({
isOpen: !currentState.isOpen
}));
}
// We close the popover on the next tick by using setTimeout.
// This is necessary because we need to first check if // another child of the element has received focus as // the blur event fires prior to the new focus event.
onBlurHandler() { this.timeOutId = setTimeout(() => { this.setState({ isOpen: false }); }); }
// If a child receives focus, do not close the popover.
onFocusHandler() { clearTimeout(this.timeOutId); }
render() {
// React assists us by bubbling the blur and // focus events to the parent.
return (
<div onBlur={this.onBlurHandler} onFocus={this.onFocusHandler}> <button onClick={this.onClickHandler}
aria-haspopup="true"
aria-expanded={this.state.isOpen}>
Select an option
</button>
{this.state.isOpen && (
<ul>
<li>Option 1</li>
<li>Option 2</li>
<li>Option 3</li>
</ul>
)}
</div>
);
}
}
This code exposes the functionality to both pointer device and keyboard users.
Also note the added aria-*
props to support screen-reader users.
For simplicity's sake the keyboard events to enable arrow key
interaction of the popover options have not been implemented.
This is one example of many cases where depending on only pointer and mouse events will break functionality for keyboard users.
Always testing with the keyboard will immediately highlight the problem areas which can then be fixed by using keyboard aware event handlers.
More Complex Widgets
A more complex user experience should not mean a less accessible one.
Whereas accessibility is most easily achieved by coding as close to HTML as possible, even the most complex widget can be coded accessibly.
Here we require knowledge of ARIA Roles as well as ARIA States and Properties.
These are toolboxes filled with HTML attributes that are fully supported in JSX and enable us to construct fully accessible, highly functional React components.
Each type of widget has a specific design pattern and is expected to function in a certain way by users and user agents alike:
- WAI-ARIA Authoring Practices - Design Patterns and Widgets
- Heydon Pickering - ARIA Examples
- Inclusive Components
Other Points for Consideration
Setting the language
Indicate the human language of page texts as screen reader software uses this to select the correct voice settings:
- WebAIM - Document Language
Setting the document title
Set the document <title>
to correctly describe the current page content as this ensures that the user remains aware of the current page context:
- WCAG - Understanding the Document Title Requirement
We can set this in React using the React Document Title Component.
Color contrast
Ensure that all readable text on your website has sufficient color contrast to remain maximally readable by users with low vision:
- WCAG - Understanding the Color Contrast Requirement
- Everything About Color Contrast And Why You Should Rethink It
- A11yProject - What is Color Contrast
It can be tedious to manually calculate the proper color combinations for all cases in your website so instead, you can calculate an entire accessible color palette with Colorable.
Both the aXe and WAVE tools mentioned below also include color contrast tests and will report on contrast errors.
If you want to extend your contrast testing abilities you can use these tools:
- WebAIM - Color Contrast Checker
- The Paciello Group - Color Contrast Analyzer
Development and Testing Tools
There are a number of tools we can use to assist in the creation of accessible web applications.
The keyboard
By far the easiest and also one of the most important checks is to test if your entire website can be reached and used with the keyboard alone.
Do this by:
- Disconnecting your mouse.
- Using
Tab
and Shift+Tab
to browse.
- Using
Enter
to activate elements.
- Where required, using your keyboard arrow keys to interact with some elements, such as menus and dropdowns.
Development assistance
We can check some accessibility features directly in our JSX code.
Often intellisense checks are already provided in JSX aware IDE's for the ARIA roles, states and properties.
We also have access to the following tool:
eslint-plugin-jsx-a11y
The eslint-plugin-jsx-a11y plugin for ESLint provides AST linting feedback regarding accessibility issues in your JSX.
Many IDE's allow you to integrate these findings directly into code analysis and source code windows.
Create React App has this plugin with a subset of rules activated.
If you want to enable even more accessibility rules, you can create an .eslintrc
file in the root of your project with this content:
{
"extends": ["react-app", "plugin:jsx-a11y/recommended"],
"plugins": ["jsx-a11y"]
}
Testing accessibility in the browser
A number of tools exist that can run accessibility audits on web pages in your browser.
Please use them in combination with other accessibility checks mentioned here as they can only
test the technical accessibility of your HTML.
aXe, aXe-core and react-axe
Deque Systems offers aXe-core for automated and end-to-end accessibility tests of your applications.
This module includes integrations for Selenium.
The Accessibility Engine or aXe, is an accessibility inspector browser extension built on aXe-core
.
You can also use the react-axe module to report these accessibility findings directly to the console while developing and debugging.
WebAIM WAVE
The Web Accessibility Evaluation Tool is another accessibility browser extension.
Accessibility inspectors and the Accessibility Tree
The Accessibility Tree is a subset of the DOM tree that contains accessible objects for every DOM element that should be exposed
to assistive technology, such as screen readers.
In some browsers we can easily view the accessibility information for each element in the accessibility tree:
- Using the Accessibility Inspector in Firefox
- Using the Accessibility Inspector in Chrome
- Using the Accessibility Inspector in OS X Safari
Screen readers
Testing with a screen reader should form part of your accessibility tests.
Please note that browser / screen reader combinations matter.
It is recommended that you test your application in the browser best suited to your screen reader of choice.
Commonly Used Screen Readers
NVDA in Firefox
NonVisual Desktop Access or NVDA is an open source Windows screen reader that is widely used.
Refer to the following guides on how to best use NVDA:
- WebAIM - Using NVDA to Evaluate Web Accessibility
- Deque - NVDA Keyboard Shortcuts
VoiceOver in Safari
VoiceOver is an integrated screen reader on Apple devices.
Refer to the following guides on how to activate and use VoiceOver:
- WebAIM - Using VoiceOver to Evaluate Web Accessibility
- Deque - VoiceOver for OS X Keyboard Shortcuts
- Deque - VoiceOver for iOS Shortcuts
JAWS in Internet Explorer
Job Access With Speech or JAWS, is a prolifically used screen reader on Windows.
Refer to the following guides on how to best use JAWS:
- WebAIM - Using JAWS to Evaluate Web Accessibility
- Deque - JAWS Keyboard Shortcuts
Other Screen Readers
ChromeVox in Google Chrome
ChromeVox is an integrated screen reader on Chromebooks and is available as an extension for Google Chrome.
Refer to the following guides on how best to use ChromeVox:
- Google Chromebook Help - Use the Built-in Screen Reader
- ChromeVox Classic Keyboard Shortcuts Reference
Code-Splitting
Bundling
Most React apps will have their files ¡°bundled¡± using tools like Webpack, Rollup or Browserify.
Bundling is the process of following imported files and merging them into a single file: a ¡°bundle¡±.
This bundle can then be included on a webpage to load an entire app at once.
Example
App:
// app.js
import { add } from './math.js';
console.log(add(16, 26)); // 42
// math.js
export function add(a, b) {
return a + b;
}
Bundle:
function add(a, b) {
return a + b;
}
console.log(add(16, 26)); // 42
Note:
Your bundles will end up looking a lot different than this.
If you're using Create React App, Next.js, Gatsby, or a similar tool, you will have a Webpack setup out of the box to bundle your app.
If you aren't, you'll need to setup bundling yourself.
For example, see the Installation and Getting Started guides on the Webpack docs.
Code Splitting
Bundling is great, but as your app grows, your bundle will grow too.
Especially if you are including large third-party libraries.
You need to keep an eye on the code you are including in your bundle so that you don't accidentally make it so large that your app takes a long time to load.
To avoid winding up with a large bundle, it's good to get ahead of the problem and start ¡°splitting¡± your bundle.
Code-Splitting is a feature
supported by bundlers like Webpack, Rollup and Browserify (via factor-bundle) which can create multiple bundles that can be dynamically loaded at runtime.
Code-splitting your app can help you ¡°lazy-load¡± just the things that are currently needed by the user, which can dramatically improve the performance of your app.
While you haven't reduced the overall amount of code in your app, you've avoided loading code that the user may never need, and reduced the amount of code needed during the initial load.
import()
The best way to introduce code-splitting into your app is through the dynamic import()
syntax.
Before:
import { add } from './math';
console.log(add(16, 26));
After:
import("./math").then(math => {
console.log(math.add(16, 26));
});
When Webpack comes across this syntax, it automatically starts code-splitting your app.
If you're using Create React App, this is already configured for you and you can start using it immediately.
It's also supported out of the box in Next.js.
If you're setting up Webpack yourself, you'll probably want to read Webpack's guide on code splitting.
Your Webpack config should look vaguely like this.
When using Babel, you'll need to make sure that Babel can parse the dynamic import syntax but is not transforming it.
For that you will need @babel/plugin-syntax-dynamic-import.
React.lazy
Note:
React.lazy
and Suspense are not yet available for server-side rendering.
If you want to do code-splitting in a server rendered app, we recommend Loadable Components.
It has a nice guide for bundle splitting with server-side rendering.
The React.lazy
function lets you render a dynamic import as a regular component.
Before:
import OtherComponent from './OtherComponent';
After:
const OtherComponent = React.lazy(() => import('./OtherComponent'));
This will automatically load the bundle containing the OtherComponent
when this component is first rendered.
React.lazy
takes a function that must call a dynamic import()
.
This must return a Promise
which resolves to a module with a default
export containing a React component.
The lazy component should then be rendered inside a Suspense
component, which allows us to show some fallback content (such as a loading indicator) while we're waiting for the lazy component to load.
import React, { Suspense } from 'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
</div>
);
}
The fallback
prop accepts any React elements that you want to render while waiting for the component to load.
You can place the Suspense
component anywhere above the lazy component.
You can even wrap multiple lazy components with a single Suspense
component.
import React, { Suspense } from 'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<section>
<OtherComponent />
<AnotherComponent />
</section>
</Suspense>
</div>
);
}
Error boundaries
If the other module fails to load (for example, due to network failure), it will trigger an error.
You can handle these errors to show a nice user experience and manage recovery with Error Boundaries.
Once you've created your Error Boundary, you can use it anywhere above your lazy components to display an error state when there's a network error.
import React, { Suspense } from 'react';
import MyErrorBoundary from './MyErrorBoundary';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));
const MyComponent = () => (
<div>
<MyErrorBoundary>
<Suspense fallback={<div>Loading...</div>}>
<section>
<OtherComponent />
<AnotherComponent />
</section>
</Suspense>
</MyErrorBoundary>
</div>
);
Route-based code splitting
Deciding where in your app to introduce code splitting can be a bit tricky.
You want to make sure you choose places that will split bundles evenly, but won't disrupt the user experience.
A good place to start is with routes.
Most people on the web are used to page transitions taking some amount of time to load.
You also tend to be re-rendering the entire page at once so your users are unlikely to be interacting with other elements on the page at the same time.
Here's an example of how to setup route-based code splitting into your app using libraries like React Router with React.lazy
.
import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));
const App = () => (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
</Switch>
</Suspense>
</Router>
);
Named Exports
React.lazy
currently only supports default exports.
If the module you want to import uses named exports, you can create an intermediate module that reexports it as the default.
This ensures that tree shaking keeps working and that you don't pull in unused components.
// ManyComponents.js
export const MyComponent = /* ...
*/;
export const MyUnusedComponent = /* ...
*/;
// MyComponent.js
export { MyComponent as default } from "./ManyComponents.js";
// MyApp.js
import React, { lazy } from 'react';
const MyComponent = lazy(() => import("./MyComponent.js"));
Context
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
In a typical React application, data is passed top-down (parent to child) via props, but this can be cumbersome for certain types of props (e.g.
locale preference, UI theme) that are required by many components within an application.
Context provides a way to share values like these between components without having to explicitly pass a prop through every level of the tree.
- When to Use Context
- Before You Use Context
-
API
- React.createContext
- Context.Provider
- Class.contextType
- Context.Consumer
- Context.displayName
-
Examples
- Dynamic Context
- Updating Context from a Nested Component
- Consuming Multiple Contexts
- Caveats
- Legacy API
When to Use Context
Context is designed to share data that can be considered ¡°global¡± for a tree of React components, such as the current authenticated user, theme, or preferred language.
For example, in the code below we manually thread through a ¡°theme¡± prop in order to style the Button component:
class App extends React.Component {
render() {
return <Toolbar theme="dark" />;
}
}
function Toolbar(props) {
// The Toolbar component must take an extra "theme" prop // and pass it to the ThemedButton.
This can become painful // if every single button in the app needs to know the theme // because it would have to be passed through all components.
return (
<div>
<ThemedButton theme={props.theme} /> </div>
);
}
class ThemedButton extends React.Component {
render() {
return <Button theme={this.props.theme} />;
}
}
Using context, we can avoid passing props through intermediate elements:
// Context lets us pass a value deep into the component tree// without explicitly threading it through every component.// Create a context for the current theme (with "light" as the default).const ThemeContext = React.createContext('light');
class App extends React.Component {
render() {
// Use a Provider to pass the current theme to the tree below.
// Any component can read it, no matter how deep it is.
// In this example, we're passing "dark" as the current value.
return (
<ThemeContext.Provider value="dark"> <Toolbar />
</ThemeContext.Provider>
);
}
}
// A component in the middle doesn't have to// pass the theme down explicitly anymore.function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
class ThemedButton extends React.Component {
// Assign a contextType to read the current theme context.
// React will find the closest theme Provider above and use its value.
// In this example, the current theme is "dark".
static contextType = ThemeContext;
render() {
return <Button theme={this.context} />; }
}
Before You Use Context
Context is primarily used when some data needs to be accessible by many components at different nesting levels.
Apply it sparingly because it makes component reuse more difficult.
If you only want to avoid passing some props through many levels, component composition is often a simpler solution than context.
For example, consider a Page
component that passes a user
and avatarSize
prop several levels down so that deeply nested Link
and Avatar
components can read it:
<Page user={user} avatarSize={avatarSize} />
// ...
which renders ...
<PageLayout user={user} avatarSize={avatarSize} />
// ...
which renders ...
<NavigationBar user={user} avatarSize={avatarSize} />
// ...
which renders ...
<Link href={user.permalink}>
<Avatar user={user} size={avatarSize} />
</Link>
It might feel redundant to pass down the user
and avatarSize
props through many levels if in the end only the Avatar
component really needs it.
It's also annoying that whenever the Avatar
component needs more props from the top, you have to add them at all the intermediate levels too.
One way to solve this issue without context is to pass down the Avatar
component itself so that the intermediate components don't need to know about the user
or avatarSize
props:
function Page(props) {
const user = props.user;
const userLink = (
<Link href={user.permalink}>
<Avatar user={user} size={props.avatarSize} />
</Link>
);
return <PageLayout userLink={userLink} />;
}
// Now, we have:
<Page user={user} avatarSize={avatarSize} />
// ...
which renders ...
<PageLayout userLink={...} />
// ...
which renders ...
<NavigationBar userLink={...} />
// ...
which renders ...
{props.userLink}
With this change, only the top-most Page component needs to know about the Link
and Avatar
components' use of user
and avatarSize
.
This inversion of control can make your code cleaner in many cases by reducing the amount of props you need to pass through your application and giving more control to the root components.
However, this isn't the right choice in every case: moving more complexity higher in the tree makes those higher-level components more complicated and forces the lower-level components to be more flexible than you may want.
You're not limited to a single child for a component.
You may pass multiple children, or even have multiple separate ¡°slots¡± for children, as documented here:
function Page(props) {
const user = props.user;
const content = <Feed user={user} />;
const topBar = (
<NavigationBar>
<Link href={user.permalink}>
<Avatar user={user} size={props.avatarSize} />
</Link>
</NavigationBar>
);
return (
<PageLayout
topBar={topBar}
content={content}
/>
);
}
This pattern is sufficient for many cases when you need to decouple a child from its immediate parents.
You can take it even further with render props if the child needs to communicate with the parent before rendering.
However, sometimes the same data needs to be accessible by many components in the tree, and at different nesting levels.
Context lets you ¡°broadcast¡± such data, and changes to it, to all components below.
Common examples where using context might be simpler than the alternatives include managing the current locale, theme, or a data cache.
API
React.createContext
const MyContext = React.createContext(defaultValue);
Creates a Context object.
When React renders a component that subscribes to this Context object it will read the current context value from the closest matching Provider
above it in the tree.
The defaultValue
argument is only used when a component does not have a matching Provider above it in the tree.
This can be helpful for testing components in isolation without wrapping them.
Note: passing undefined
as a Provider value does not cause consuming components to use defaultValue
.
Context.Provider
<MyContext.Provider value={/* some value */}>
Every Context object comes with a Provider React component that allows consuming components to subscribe to context changes.
The Provider component accepts a value
prop to be passed to consuming components that are descendants of this Provider.
One Provider can be connected to many consumers.
Providers can be nested to override values deeper within the tree.
All consumers that are descendants of a Provider will re-render whenever the Provider's value
prop changes.
The propagation from Provider to its descendant consumers (including .contextType
and useContext
) is not subject to the shouldComponentUpdate
method, so the consumer is updated even when an ancestor component skips an update.
Changes are determined by comparing the new and old values using the same algorithm as Object.is
.
Note
The way changes are determined can cause some issues when passing objects as value
: see Caveats.
Class.contextType
class MyClass extends React.Component {
componentDidMount() {
let value = this.context;
/* perform a side-effect at mount using the value of MyContext */
}
componentDidUpdate() {
let value = this.context;
/* ...
*/
}
componentWillUnmount() {
let value = this.context;
/* ...
*/
}
render() {
let value = this.context;
/* render something based on the value of MyContext */
}
}
MyClass.contextType = MyContext;
The contextType
property on a class can be assigned a Context object created by React.createContext()
.
This lets you consume the nearest current value of that Context type using this.context
.
You can reference this in any of the lifecycle methods including the render function.
Note:
You can only subscribe to a single context using this API.
If you need to read more than one see Consuming Multiple Contexts.
If you are using the experimental public class fields syntax, you can use a static class field to initialize your contextType
.
class MyClass extends React.Component {
static contextType = MyContext;
render() {
let value = this.context;
/* render something based on the value */
}
}
Context.Consumer
<MyContext.Consumer>
{value => /* render something based on the context value */}
</MyContext.Consumer>
A React component that subscribes to context changes.
This lets you subscribe to a context within a function component.
Requires a function as a child.
The function receives the current context value and returns a React node.
The value
argument passed to the function will be equal to the value
prop of the closest Provider for this context above in the tree.
If there is no Provider for this context above, the value
argument will be equal to the defaultValue
that was passed to createContext()
.
Note
For more information about the ¡®function as a child' pattern, see render props.
Context.displayName
Context object accepts a displayName
string property.
React DevTools uses this string to determine what to display for the context.
For example, the following component will appear as MyDisplayName in the DevTools:
const MyContext = React.createContext(/* some value */);
MyContext.displayName = 'MyDisplayName';
<MyContext.Provider> // "MyDisplayName.Provider" in DevTools
<MyContext.Consumer> // "MyDisplayName.Consumer" in DevTools
Examples
Dynamic Context
A more complex example with dynamic values for the theme:
theme-context.js
export const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
};
export const ThemeContext = React.createContext( themes.dark // default value);
themed-button.js
import {ThemeContext} from './theme-context';
class ThemedButton extends React.Component {
render() {
let props = this.props;
let theme = this.context; return (
<button
{...props}
style={{backgroundColor: theme.background}}
/>
);
}
}
ThemedButton.contextType = ThemeContext;
export default ThemedButton;
app.js
import {ThemeContext, themes} from './theme-context';
import ThemedButton from './themed-button';
// An intermediate component that uses the ThemedButton
function Toolbar(props) {
return (
<ThemedButton onClick={props.changeTheme}>
Change Theme
</ThemedButton>
);
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
theme: themes.light,
};
this.toggleTheme = () => {
this.setState(state => ({
theme:
state.theme === themes.dark
? themes.light
: themes.dark,
}));
};
}
render() {
// The ThemedButton button inside the ThemeProvider // uses the theme from state while the one outside uses // the default dark theme return (
<Page>
<ThemeContext.Provider value={this.state.theme}> <Toolbar changeTheme={this.toggleTheme} /> </ThemeContext.Provider> <Section>
<ThemedButton /> </Section>
</Page>
);
}
}
ReactDOM.render(<App />, document.root);
Updating Context from a Nested Component
It is often necessary to update the context from a component that is nested somewhere deeply in the component tree.
In this case you can pass a function down through the context to allow consumers to update the context:
theme-context.js
// Make sure the shape of the default value passed to
// createContext matches the shape that the consumers expect!
export const ThemeContext = React.createContext({
theme: themes.dark, toggleTheme: () => {},});
theme-toggler-button.js
import {ThemeContext} from './theme-context';
function ThemeTogglerButton() {
// The Theme Toggler Button receives not only the theme // but also a toggleTheme function from the context return (
<ThemeContext.Consumer>
{({theme, toggleTheme}) => ( <button
onClick={toggleTheme}
style={{backgroundColor: theme.background}}>
Toggle Theme
</button>
)}
</ThemeContext.Consumer>
);
}
export default ThemeTogglerButton;
app.js
import {ThemeContext, themes} from './theme-context';
import ThemeTogglerButton from './theme-toggler-button';
class App extends React.Component {
constructor(props) {
super(props);
this.toggleTheme = () => {
this.setState(state => ({
theme:
state.theme === themes.dark
? themes.light
: themes.dark,
}));
};
// State also contains the updater function so it will // be passed down into the context provider this.state = {
theme: themes.light,
toggleTheme: this.toggleTheme, };
}
render() {
// The entire state is passed to the provider return (
<ThemeContext.Provider value={this.state}> <Content />
</ThemeContext.Provider>
);
}
}
function Content() {
return (
<div>
<ThemeTogglerButton />
</div>
);
}
ReactDOM.render(<App />, document.root);
Consuming Multiple Contexts
To keep context re-rendering fast, React needs to make each context consumer a separate node in the tree.
// Theme context, default to light theme
const ThemeContext = React.createContext('light');
// Signed-in user context
const UserContext = React.createContext({
name: 'Guest',
});
class App extends React.Component {
render() {
const {signedInUser, theme} = this.props;
// App component that provides initial context values
return (
<ThemeContext.Provider value={theme}> <UserContext.Provider value={signedInUser}> <Layout />
</UserContext.Provider> </ThemeContext.Provider> );
}
}
function Layout() {
return (
<div>
<Sidebar />
<Content />
</div>
);
}
// A component may consume multiple contexts
function Content() {
return (
<ThemeContext.Consumer> {theme => ( <UserContext.Consumer> {user => ( <ProfilePage user={user} theme={theme} /> )} </UserContext.Consumer> )} </ThemeContext.Consumer> );
}
If two or more context values are often used together, you might want to consider creating your own render prop component that provides both.
Caveats
Because context uses reference identity to determine when to re-render, there are some gotchas that could trigger unintentional renders in consumers when a provider's parent re-renders.
For example, the code below will re-render all consumers every time the Provider re-renders because a new object is always created for value
:
class App extends React.Component {
render() {
return (
<MyContext.Provider value={{something: 'something'}}> <Toolbar />
</MyContext.Provider>
);
}
}
To get around this, lift the value into the parent's state:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: {something: 'something'}, };
}
render() {
return (
<Provider value={this.state.value}> <Toolbar />
</Provider>
);
}
}
Legacy API
Note
React previously shipped with an experimental context API.
The old API will be supported in all 16.x releases, but applications using it should migrate to the new version.
The legacy API will be removed in a future major React version.
Read the legacy context docs here.
Error Boundaries
In the past, JavaScript errors inside components used to corrupt React's internal state and cause it to emit cryptic errors on next renders.
These errors were always caused by an earlier error in the application code, but React did not provide a way to handle them gracefully in components, and could not recover from them.
Introducing Error Boundaries
A JavaScript error in a part of the UI shouldn't break the whole app.
To solve this problem for React users, React 16 introduces a new concept of an ¡°error boundary¡±.
Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed.
Error boundaries catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them.
Note
Error boundaries do not catch errors for:
- Event handlers (learn more)
- Asynchronous code (e.g.
setTimeout
or requestAnimationFrame
callbacks)
- Server side rendering
- Errors thrown in the error boundary itself (rather than its children)
A class component becomes an error boundary if it defines either (or both) of the lifecycle methods static getDerivedStateFromError()
or componentDidCatch()
.
Use static getDerivedStateFromError()
to render a fallback UI after an error has been thrown.
Use componentDidCatch()
to log error information.
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) { // Update state so the next render will show the fallback UI.
return { hasError: true }; }
componentDidCatch(error, errorInfo) { // You can also log the error to an error reporting service logErrorToMyService(error, errorInfo); }
render() {
if (this.state.hasError) { // You can render any custom fallback UI return <h2>Something went wrong.</h2>; }
return this.props.children;
}
}
Then you can use it as a regular component:
<ErrorBoundary>
<MyWidget />
</ErrorBoundary>
Error boundaries work like a JavaScript catch {}
block, but for components.
Only class components can be error boundaries.
In practice, most of the time you'll want to declare an error boundary component once and use it throughout your application.
Note that error boundaries only catch errors in the components below them in the tree.
An error boundary can't catch an error within itself.
If an error boundary fails trying to render the error message, the error will propagate to the closest error boundary above it.
This, too, is similar to how catch {} block works in JavaScript.
Live Demo
Check out this example of declaring and using an error boundary with React 16.
Where to Place Error Boundaries
The granularity of error boundaries is up to you.
You may wrap top-level route components to display a ¡°Something went wrong¡± message to the user, just like server-side frameworks often handle crashes.
You may also wrap individual widgets in an error boundary to protect them from crashing the rest of the application.
New Behavior for Uncaught Errors
This change has an important implication.
As of React 16, errors that were not caught by any error boundary will result in unmounting of the whole React component tree.
We debated this decision, but in our experience it is worse to leave corrupted UI in place than to completely remove it.
For example, in a product like Messenger leaving the broken UI visible could lead to somebody sending a message to the wrong person.
Similarly, it is worse for a payments app to display a wrong amount than to render nothing.
This change means that as you migrate to React 16, you will likely uncover existing crashes in your application that have been unnoticed before.
Adding error boundaries lets you provide better user experience when something goes wrong.
For example, Facebook Messenger wraps content of the sidebar, the info panel, the conversation log, and the message input into separate error boundaries.
If some component in one of these UI areas crashes, the rest of them remain interactive.
We also encourage you to use JS error reporting services (or build your own) so that you can learn about unhandled exceptions as they happen in production, and fix them.
Component Stack Traces
React 16 prints all errors that occurred during rendering to the console in development, even if the application accidentally swallows them.
In addition to the error message and the JavaScript stack, it also provides component stack traces.
Now you can see where exactly in the component tree the failure has happened:
You can also see the filenames and line numbers in the component stack trace.
This works by default in Create React App projects:
If you don't use Create React App, you can add this plugin manually to your Babel configuration.
Note that it's intended only for development and must be disabled in production.
Note
Component names displayed in the stack traces depend on the Function.name
property.
If you support older browsers and devices which may not yet provide this natively (e.g.
IE 11), consider including a Function.name
polyfill in your bundled application, such as function.name-polyfill
.
Alternatively, you may explicitly set the displayName
property on all your components.
How About try/catch?
try
/ catch
is great but it only works for imperative code:
try {
showButton();
} catch (error) {
// ...
}
However, React components are declarative and specify what should be rendered:
<Button />
Error boundaries preserve the declarative nature of React, and behave as you would expect.
For example, even if an error occurs in a componentDidUpdate
method caused by a setState
somewhere deep in the tree, it will still correctly propagate to the closest error boundary.
How About Event Handlers?
Error boundaries do not catch errors inside event handlers.
React doesn't need error boundaries to recover from errors in event handlers.
Unlike the render method and lifecycle methods, the event handlers don't happen during rendering.
So if they throw, React still knows what to display on the screen.
If you need to catch an error inside event handler, use the regular JavaScript try
/ catch
statement:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { error: null };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
try { // Do something that could throw } catch (error) { this.setState({ error }); } }
render() {
if (this.state.error) { return <h2>Caught an error.</h2> } return <button onClick={this.handleClick}>Click Me</button> }
}
Note that the above example is demonstrating regular JavaScript behavior and doesn't use error boundaries.
Naming Changes from React 15
React 15 included a very limited support for error boundaries under a different method name: unstable_handleError
.
This method no longer works, and you will need to change it to componentDidCatch
in your code starting from the first 16 beta release.
For this change, we've provided a codemod to automatically migrate your code.
Forwarding Refs
Ref forwarding is a technique for automatically passing a ref through a component to one of its children.
This is typically not necessary for most components in the application.
However, it can be useful for some kinds of components, especially in reusable component libraries.
The most common scenarios are described below.
Forwarding refs to DOM components
Consider a FancyButton
component that renders the native button
DOM element:
function FancyButton(props) {
return (
<button className="FancyButton">
{props.children}
</button>
);
}
React components hide their implementation details, including their rendered output.
Other components using FancyButton
usually will not need to obtain a ref to the inner button
DOM element.
This is good because it prevents components from relying on each other's DOM structure too much.
Although such encapsulation is desirable for application-level components like FeedStory
or Comment
, it can be inconvenient for highly reusable ¡°leaf¡± components like FancyButton
or MyTextInput
.
These components tend to be used throughout the application in a similar manner as a regular DOM button
and input
, and accessing their DOM nodes may be unavoidable for managing focus, selection, or animations.
Ref forwarding is an opt-in feature that lets some components take a ref
they receive, and pass it further down (in other words, ¡°forward¡± it) to a child.
In the example below, FancyButton
uses React.forwardRef
to obtain the ref
passed to it, and then forward it to the DOM button
that it renders:
const FancyButton = React.forwardRef((props, ref) => ( <button ref={ref} className="FancyButton"> {props.children}
</button>
));
// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
This way, components using FancyButton
can get a ref to the underlying button
DOM node and access it if necessary¡ªjust like if they used a DOM button
directly.
Here is a step-by-step explanation of what happens in the above example:
- We create a React ref by calling
React.createRef
and assign it to a ref
variable.
- We pass our
ref
down to <FancyButton ref={ref}>
by specifying it as a JSX attribute.
- React passes the
ref
to the (props, ref) => ...
function inside forwardRef
as a second argument.
- We forward this
ref
argument down to <button ref={ref}>
by specifying it as a JSX attribute.
- When the ref is attached,
ref.current
will point to the <button>
DOM node.
Note
The second ref
argument only exists when you define a component with React.forwardRef
call.
Regular function or class components don't receive the ref
argument, and ref is not available in props either.
Ref forwarding is not limited to DOM components.
You can forward refs to class component instances, too.
Note for component library maintainers
When you start using forwardRef
in a component library, you should treat it as a breaking change and release a new major version of your library. This is because your library likely has an observably different behavior (such as what refs get assigned to, and what types are exported), and this can break apps and other libraries that depend on the old behavior.
Conditionally applying React.forwardRef
when it exists is also not recommended for the same reasons: it changes how your library behaves and can break your users' apps when they upgrade React itself.
Forwarding refs in higher-order components
This technique can also be particularly useful with higher-order components (also known as HOCs).
Let's start with an example HOC that logs component props to the console:
function logProps(WrappedComponent) { class LogProps extends React.Component {
componentDidUpdate(prevProps) {
console.log('old props:', prevProps);
console.log('new props:', this.props);
}
render() {
return <WrappedComponent {...this.props} />; }
}
return LogProps;
}
The ¡°logProps¡± HOC passes all props
through to the component it wraps, so the rendered output will be the same.
For example, we can use this HOC to log all props that get passed to our ¡°fancy button¡± component:
class FancyButton extends React.Component {
focus() {
// ...
}
// ...
}
// Rather than exporting FancyButton, we export LogProps.
// It will render a FancyButton though.
export default logProps(FancyButton);
There is one caveat to the above example: refs will not get passed through.
That's because ref
is not a prop.
Like key
, it's handled differently by React.
If you add a ref to a HOC, the ref will refer to the outermost container component, not the wrapped component.
This means that refs intended for our FancyButton
component will actually be attached to the LogProps
component:
import FancyButton from './FancyButton';
const ref = React.createRef();
// The FancyButton component we imported is the LogProps HOC.
// Even though the rendered output will be the same,
// Our ref will point to LogProps instead of the inner FancyButton component!
// This means we can't call e.g.
ref.current.focus()
<FancyButton
label="Click Me"
handleClick={handleClick}
ref={ref}/>;
Fortunately, we can explicitly forward refs to the inner FancyButton
component using the React.forwardRef
API.
React.forwardRef
accepts a render function that receives props
and ref
parameters and returns a React node.
For example:
function logProps(Component) {
class LogProps extends React.Component {
componentDidUpdate(prevProps) {
console.log('old props:', prevProps);
console.log('new props:', this.props);
}
render() {
const {forwardedRef, ...rest} = this.props;
// Assign the custom prop "forwardedRef" as a ref
return <Component ref={forwardedRef} {...rest} />; }
}
// Note the second param "ref" provided by React.forwardRef.
// We can pass it along to LogProps as a regular prop, e.g.
"forwardedRef"
// And it can then be attached to the Component.
return React.forwardRef((props, ref) => { return <LogProps {...props} forwardedRef={ref} />; });}
Displaying a custom name in DevTools
React.forwardRef
accepts a render function.
React DevTools uses this function to determine what to display for the ref forwarding component.
For example, the following component will appear as ¡±ForwardRef¡± in the DevTools:
const WrappedComponent = React.forwardRef((props, ref) => {
return <LogProps {...props} forwardedRef={ref} />;
});
If you name the render function, DevTools will also include its name (e.g.
¡±ForwardRef(myFunction)¡±):
const WrappedComponent = React.forwardRef(
function myFunction(props, ref) {
return <LogProps {...props} forwardedRef={ref} />;
}
);
You can even set the function's displayName
property to include the component you're wrapping:
function logProps(Component) {
class LogProps extends React.Component {
// ...
}
function forwardRef(props, ref) {
return <LogProps {...props} forwardedRef={ref} />;
}
// Give this component a more helpful display name in DevTools.
// e.g.
"ForwardRef(logProps(MyComponent))"
const name = Component.displayName || Component.name; forwardRef.displayName = `logProps(${name})`;
return React.forwardRef(forwardRef);
}
Fragments
A common pattern in React is for a component to return multiple elements.
Fragments let you group a list of children without adding extra nodes to the DOM.
render() {
return (
<React.Fragment>
<ChildA />
<ChildB />
<ChildC />
</React.Fragment>
);
}
There is also a new short syntax for declaring them.
Motivation
A common pattern is for a component to return a list of children.
Take this example React snippet:
class Table extends React.Component {
render() {
return (
<table>
<tr>
<Columns />
</tr>
</table>
);
}
}
<Columns />
would need to return multiple <td>
elements in order for the rendered HTML to be valid.
If a parent div was used inside the render()
of <Columns />
, then the resulting HTML will be invalid.
class Columns extends React.Component {
render() {
return (
<div>
<td>Hello</td>
<td>World</td>
</div>
);
}
}
results in a <Table />
output of:
<table>
<tr>
<div>
<td>Hello</td>
<td>World</td>
</div>
</tr>
</table>
Fragments solve this problem.
Usage
class Columns extends React.Component {
render() {
return (
<React.Fragment> <td>Hello</td>
<td>World</td>
</React.Fragment> );
}
}
which results in a correct <Table />
output of:
<table>
<tr>
<td>Hello</td>
<td>World</td>
</tr>
</table>
Short Syntax
There is a new, shorter syntax you can use for declaring fragments.
It looks like empty tags:
class Columns extends React.Component {
render() {
return (
<> <td>Hello</td>
<td>World</td>
</> );
}
}
You can use <></>
the same way you'd use any other element except that it doesn't support keys or attributes.
Keyed Fragments
Fragments declared with the explicit <React.Fragment>
syntax may have keys.
A use case for this is mapping a collection to an array of fragments ¡ª for example, to create a description list:
function Glossary(props) {
return (
<dl>
{props.items.map(item => (
// Without the `key`, React will fire a key warning
<React.Fragment key={item.id}>
<dt>{item.term}</dt>
<dd>{item.description}</dd>
</React.Fragment>
))}
</dl>
);
}
key
is the only attribute that can be passed to Fragment
.
In the future, we may add support for additional attributes, such as event handlers.
Live Demo
You can try out the new JSX fragment syntax with this CodePen.
Higher-Order Components
A higher-order component (HOC) is an advanced technique in React for reusing component logic.
HOCs are not part of the React API, per se.
They are a pattern that emerges from React's compositional nature.
Concretely, a higher-order component is a function that takes a component and returns a new component.
const EnhancedComponent = higherOrderComponent(WrappedComponent);
Whereas a component transforms props into UI, a higher-order component transforms a component into another component.
HOCs are common in third-party React libraries, such as Redux's connect
and Relay's createFragmentContainer
.
In this document, we'll discuss why higher-order components are useful, and how to write your own.
Use HOCs For Cross-Cutting Concerns
Note
We previously recommended mixins as a way to handle cross-cutting concerns.
We've since realized that mixins create more trouble than they are worth.
Read more about why we've moved away from mixins and how you can transition your existing components.
Components are the primary unit of code reuse in React.
However, you'll find that some patterns aren't a straightforward fit for traditional components.
For example, say you have a CommentList
component that subscribes to an external data source to render a list of comments:
class CommentList extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
// "DataSource" is some global data source
comments: DataSource.getComments()
};
}
componentDidMount() {
// Subscribe to changes
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
// Clean up listener
DataSource.removeChangeListener(this.handleChange);
}
handleChange() {
// Update component state whenever the data source changes
this.setState({
comments: DataSource.getComments()
});
}
render() {
return (
<div>
{this.state.comments.map((comment) => (
<Comment comment={comment} key={comment.id} />
))}
</div>
);
}
}
Later, you write a component for subscribing to a single blog post, which follows a similar pattern:
class BlogPost extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
blogPost: DataSource.getBlogPost(props.id)
};
}
componentDidMount() {
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
DataSource.removeChangeListener(this.handleChange);
}
handleChange() {
this.setState({
blogPost: DataSource.getBlogPost(this.props.id)
});
}
render() {
return <TextBlock text={this.state.blogPost} />;
}
}
CommentList
and BlogPost
aren't identical ¡ª they call different methods on DataSource
, and they render different output.
But much of their implementation is the same:
- On mount, add a change listener to
DataSource
.
- Inside the listener, call
setState
whenever the data source changes.
- On unmount, remove the change listener.
You can imagine that in a large app, this same pattern of subscribing to DataSource
and calling setState
will occur over and over again.
We want an abstraction that allows us to define this logic in a single place and share it across many components.
This is where higher-order components excel.
We can write a function that creates components, like CommentList
and BlogPost
, that subscribe to DataSource
.
The function will accept as one of its arguments a child component that receives the subscribed data as a prop.
Let's call the function withSubscription
:
const CommentListWithSubscription = withSubscription(
CommentList,
(DataSource) => DataSource.getComments()
);
const BlogPostWithSubscription = withSubscription(
BlogPost,
(DataSource, props) => DataSource.getBlogPost(props.id)
);
The first parameter is the wrapped component.
The second parameter retrieves the data we're interested in, given a DataSource
and the current props.
When CommentListWithSubscription
and BlogPostWithSubscription
are rendered, CommentList
and BlogPost
will be passed a data
prop with the most current data retrieved from DataSource
:
// This function takes a component...
function withSubscription(WrappedComponent, selectData) {
// ...and returns another component...
return class extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
data: selectData(DataSource, props)
};
}
componentDidMount() {
// ...
that takes care of the subscription...
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
DataSource.removeChangeListener(this.handleChange);
}
handleChange() {
this.setState({
data: selectData(DataSource, this.props)
});
}
render() {
// ...
and renders the wrapped component with the fresh data!
// Notice that we pass through any additional props
return <WrappedComponent data={this.state.data} {...this.props} />;
}
};
}
Note that a HOC doesn't modify the input component, nor does it use inheritance to copy its behavior.
Rather, a HOC composes the original component by wrapping it in a container component.
A HOC is a pure function with zero side-effects.
And that's it! The wrapped component receives all the props of the container, along with a new prop, data
, which it uses to render its output.
The HOC isn't concerned with how or why the data is used, and the wrapped component isn't concerned with where the data came from.
Because withSubscription
is a normal function, you can add as many or as few arguments as you like.
For example, you may want to make the name of the data
prop configurable, to further isolate the HOC from the wrapped component.
Or you could accept an argument that configures shouldComponentUpdate
, or one that configures the data source.
These are all possible because the HOC has full control over how the component is defined.
Like components, the contract between withSubscription
and the wrapped component is entirely props-based.
This makes it easy to swap one HOC for a different one, as long as they provide the same props to the wrapped component.
This may be useful if you change data-fetching libraries, for example.
Don't Mutate the Original Component.
Use Composition.
Resist the temptation to modify a component's prototype (or otherwise mutate it) inside a HOC.
function logProps(InputComponent) {
InputComponent.prototype.componentDidUpdate = function(prevProps) {
console.log('Current props: ', this.props);
console.log('Previous props: ', prevProps);
};
// The fact that we're returning the original input is a hint that it has
// been mutated.
return InputComponent;
}
// EnhancedComponent will log whenever props are received
const EnhancedComponent = logProps(InputComponent);
There are a few problems with this.
One is that the input component cannot be reused separately from the enhanced component.
More crucially, if you apply another HOC to EnhancedComponent
that also mutates componentDidUpdate
, the first HOC's functionality will be overridden! This HOC also won't work with function components, which do not have lifecycle methods.
Mutating HOCs are a leaky abstraction¡ªthe consumer must know how they are implemented in order to avoid conflicts with other HOCs.
Instead of mutation, HOCs should use composition, by wrapping the input component in a container component:
function logProps(WrappedComponent) {
return class extends React.Component {
componentDidUpdate(prevProps) {
console.log('Current props: ', this.props);
console.log('Previous props: ', prevProps);
}
render() {
// Wraps the input component in a container, without mutating it.
Good!
return <WrappedComponent {...this.props} />;
}
}
}
This HOC has the same functionality as the mutating version while avoiding the potential for clashes.
It works equally well with class and function components.
And because it's a pure function, it's composable with other HOCs, or even with itself.
You may have noticed similarities between HOCs and a pattern called container components.
Container components are part of a strategy of separating responsibility between high-level and low-level concerns.
Containers manage things like subscriptions and state, and pass props to components that handle things like rendering UI.
HOCs use containers as part of their implementation.
You can think of HOCs as parameterized container component definitions.
Convention: Pass Unrelated Props Through to the Wrapped Component
HOCs add features to a component.
They shouldn't drastically alter its contract.
It's expected that the component returned from a HOC has a similar interface to the wrapped component.
HOCs should pass through props that are unrelated to its specific concern.
Most HOCs contain a render method that looks something like this:
render() {
// Filter out extra props that are specific to this HOC and shouldn't be
// passed through
const { extraProp, ...passThroughProps } = this.props;
// Inject props into the wrapped component.
These are usually state values or
// instance methods.
const injectedProp = someStateOrInstanceMethod;
// Pass props to wrapped component
return (
<WrappedComponent
injectedProp={injectedProp}
{...passThroughProps}
/>
);
}
This convention helps ensure that HOCs are as flexible and reusable as possible.
Convention: Maximizing Composability
Not all HOCs look the same.
Sometimes they accept only a single argument, the wrapped component:
const NavbarWithRouter = withRouter(Navbar);
Usually, HOCs accept additional arguments.
In this example from Relay, a config object is used to specify a component's data dependencies:
const CommentWithRelay = Relay.createContainer(Comment, config);
The most common signature for HOCs looks like this:
// React Redux's `connect`
const ConnectedComment = connect(commentSelector, commentActions)(CommentList);
What?! If you break it apart, it's easier to see what's going on.
// connect is a function that returns another function
const enhance = connect(commentListSelector, commentListActions);
// The returned function is a HOC, which returns a component that is connected
// to the Redux store
const ConnectedComment = enhance(CommentList);
In other words, connect
is a higher-order function that returns a higher-order component!
This form may seem confusing or unnecessary, but it has a useful property.
Single-argument HOCs like the one returned by the connect
function have the signature Component => Component
.
Functions whose output type is the same as its input type are really easy to compose together.
// Instead of doing this...
const EnhancedComponent = withRouter(connect(commentSelector)(WrappedComponent))
// ...
you can use a function composition utility
// compose(f, g, h) is the same as (...args) => f(g(h(...args)))
const enhance = compose(
// These are both single-argument HOCs
withRouter,
connect(commentSelector)
)
const EnhancedComponent = enhance(WrappedComponent)
(This same property also allows connect
and other enhancer-style HOCs to be used as decorators, an experimental JavaScript proposal.)
The compose
utility function is provided by many third-party libraries including lodash (as lodash.flowRight
), Redux, and Ramda.
Convention: Wrap the Display Name for Easy Debugging
The container components created by HOCs show up in the React Developer Tools like any other component.
To ease debugging, choose a display name that communicates that it's the result of a HOC.
The most common technique is to wrap the display name of the wrapped component.
So if your higher-order component is named withSubscription
, and the wrapped component's display name is CommentList
, use the display name WithSubscription(CommentList)
:
function withSubscription(WrappedComponent) {
class WithSubscription extends React.Component {/* ...
*/}
WithSubscription.displayName = `WithSubscription(${getDisplayName(WrappedComponent)})`;
return WithSubscription;
}
function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName || WrappedComponent.name || 'Component';
}
Caveats
Higher-order components come with a few caveats that aren't immediately obvious if you're new to React.
Don't Use HOCs Inside the render Method
React's diffing algorithm (called Reconciliation) uses component identity to determine whether it should update the existing subtree or throw it away and mount a new one.
If the component returned from render
is identical (===
) to the component from the previous render, React recursively updates the subtree by diffing it with the new one.
If they're not equal, the previous subtree is unmounted completely.
Normally, you shouldn't need to think about this.
But it matters for HOCs because it means you can't apply a HOC to a component within the render method of a component:
render() {
// A new version of EnhancedComponent is created on every render
// EnhancedComponent1 !== EnhancedComponent2
const EnhancedComponent = enhance(MyComponent);
// That causes the entire subtree to unmount/remount each time!
return <EnhancedComponent />;
}
The problem here isn't just about performance ¡ª remounting a component causes the state of that component and all of its children to be lost.
Instead, apply HOCs outside the component definition so that the resulting component is created only once.
Then, its identity will be consistent across renders.
This is usually what you want, anyway.
In those rare cases where you need to apply a HOC dynamically, you can also do it inside a component's lifecycle methods or its constructor.
Static Methods Must Be Copied Over
Sometimes it's useful to define a static method on a React component.
For example, Relay containers expose a static method getFragment
to facilitate the composition of GraphQL fragments.
When you apply a HOC to a component, though, the original component is wrapped with a container component.
That means the new component does not have any of the static methods of the original component.
// Define a static method
WrappedComponent.staticMethod = function() {/*...*/}
// Now apply a HOC
const EnhancedComponent = enhance(WrappedComponent);
// The enhanced component has no static method
typeof EnhancedComponent.staticMethod === 'undefined' // true
To solve this, you could copy the methods onto the container before returning it:
function enhance(WrappedComponent) {
class Enhance extends React.Component {/*...*/}
// Must know exactly which method(s) to copy :(
Enhance.staticMethod = WrappedComponent.staticMethod;
return Enhance;
}
However, this requires you to know exactly which methods need to be copied.
You can use hoist-non-react-statics to automatically copy all non-React static methods:
import hoistNonReactStatic from 'hoist-non-react-statics';
function enhance(WrappedComponent) {
class Enhance extends React.Component {/*...*/}
hoistNonReactStatic(Enhance, WrappedComponent);
return Enhance;
}
Another possible solution is to export the static method separately from the component itself.
// Instead of...
MyComponent.someFunction = someFunction;
export default MyComponent;
// ...export the method separately...
export { someFunction };
// ...and in the consuming module, import both
import MyComponent, { someFunction } from './MyComponent.js';
Refs Aren't Passed Through
While the convention for higher-order components is to pass through all props to the wrapped component, this does not work for refs.
That's because ref
is not really a prop ¡ª like key
, it's handled specially by React.
If you add a ref to an element whose component is the result of a HOC, the ref refers to an instance of the outermost container component, not the wrapped component.
The solution for this problem is to use the React.forwardRef
API (introduced with React 16.3).
Learn more about it in the forwarding refs section.
Integrating with Other Libraries
React can be used in any web application.
It can be embedded in other applications and, with a little care, other applications can be embedded in React.
This guide will examine some of the more common use cases, focusing on integration with jQuery and Backbone, but the same ideas can be applied to integrating components with any existing code.
Integrating with DOM Manipulation Plugins
React is unaware of changes made to the DOM outside of React.
It determines updates based on its own internal representation, and if the same DOM nodes are manipulated by another library, React gets confused and has no way to recover.
This does not mean it is impossible or even necessarily difficult to combine React with other ways of affecting the DOM, you just have to be mindful of what each is doing.
The easiest way to avoid conflicts is to prevent the React component from updating.
You can do this by rendering elements that React has no reason to update, like an empty <div />
.
How to Approach the Problem
To demonstrate this, let's sketch out a wrapper for a generic jQuery plugin.
We will attach a ref to the root DOM element.
Inside componentDidMount
, we will get a reference to it so we can pass it to the jQuery plugin.
To prevent React from touching the DOM after mounting, we will return an empty <div />
from the render()
method.
The <div />
element has no properties or children, so React has no reason to update it, leaving the jQuery plugin free to manage that part of the DOM:
class SomePlugin extends React.Component {
componentDidMount() {
this.$el = $(this.el); this.$el.somePlugin(); }
componentWillUnmount() {
this.$el.somePlugin('destroy'); }
render() {
return <div ref={el => this.el = el} />; }
}
Note that we defined both componentDidMount
and componentWillUnmount
lifecycle methods.
Many jQuery plugins attach event listeners to the DOM so it's important to detach them in componentWillUnmount
.
If the plugin does not provide a method for cleanup, you will probably have to provide your own, remembering to remove any event listeners the plugin registered to prevent memory leaks.
Integrating with jQuery Chosen Plugin
For a more concrete example of these concepts, let's write a minimal wrapper for the plugin Chosen, which augments <select>
inputs.
Note:
Just because it's possible, doesn't mean that it's the best approach for React apps.
We encourage you to use React components when you can.
React components are easier to reuse in React applications, and often provide more control over their behavior and appearance.
First, let's look at what Chosen does to the DOM.
If you call it on a <select>
DOM node, it reads the attributes off of the original DOM node, hides it with an inline style, and then appends a separate DOM node with its own visual representation right after the <select>
.
Then it fires jQuery events to notify us about the changes.
Let's say that this is the API we're striving for with our <Chosen>
wrapper React component:
function Example() {
return (
<Chosen onChange={value => console.log(value)}>
<option>vanilla</option>
<option>chocolate</option>
<option>strawberry</option>
</Chosen>
);
}
We will implement it as an uncontrolled component for simplicity.
First, we will create an empty component with a render()
method where we return <select>
wrapped in a <div>
:
class Chosen extends React.Component {
render() {
return (
<div> <select className="Chosen-select" ref={el => this.el = el}> {this.props.children}
</select>
</div>
);
}
}
Notice how we wrapped <select>
in an extra <div>
.
This is necessary because Chosen will append another DOM element right after the <select>
node we passed to it.
However, as far as React is concerned, <div>
always only has a single child.
This is how we ensure that React updates won't conflict with the extra DOM node appended by Chosen.
It is important that if you modify the DOM outside of React flow, you must ensure React doesn't have a reason to touch those DOM nodes.
Next, we will implement the lifecycle methods.
We need to initialize Chosen with the ref to the <select>
node in componentDidMount
, and tear it down in componentWillUnmount
:
componentDidMount() {
this.$el = $(this.el); this.$el.chosen();}
componentWillUnmount() {
this.$el.chosen('destroy');}
Try it on CodePen
Note that React assigns no special meaning to the this.el
field.
It only works because we have previously assigned this field from a ref
in the render()
method:
<select className="Chosen-select" ref={el => this.el = el}>
This is enough to get our component to render, but we also want to be notified about the value changes.
To do this, we will subscribe to the jQuery change
event on the <select>
managed by Chosen.
We won't pass this.props.onChange
directly to Chosen because component's props might change over time, and that includes event handlers.
Instead, we will declare a handleChange()
method that calls this.props.onChange
, and subscribe it to the jQuery change
event:
componentDidMount() {
this.$el = $(this.el);
this.$el.chosen();
this.handleChange = this.handleChange.bind(this); this.$el.on('change', this.handleChange);}
componentWillUnmount() {
this.$el.off('change', this.handleChange); this.$el.chosen('destroy');
}
handleChange(e) { this.props.onChange(e.target.value);}
Try it on CodePen
Finally, there is one more thing left to do.
In React, props can change over time.
For example, the <Chosen>
component can get different children if parent component's state changes.
This means that at integration points it is important that we manually update the DOM in response to prop updates, since we no longer let React manage the DOM for us.
Chosen's documentation suggests that we can use jQuery trigger()
API to notify it about changes to the original DOM element.
We will let React take care of updating this.props.children
inside <select>
, but we will also add a componentDidUpdate()
lifecycle method that notifies Chosen about changes in the children list:
componentDidUpdate(prevProps) {
if (prevProps.children !== this.props.children) { this.$el.trigger("chosen:updated"); }
}
This way, Chosen will know to update its DOM element when the <select>
children managed by React change.
The complete implementation of the Chosen
component looks like this:
class Chosen extends React.Component {
componentDidMount() {
this.$el = $(this.el);
this.$el.chosen();
this.handleChange = this.handleChange.bind(this);
this.$el.on('change', this.handleChange);
}
componentDidUpdate(prevProps) {
if (prevProps.children !== this.props.children) {
this.$el.trigger("chosen:updated");
}
}
componentWillUnmount() {
this.$el.off('change', this.handleChange);
this.$el.chosen('destroy');
}
handleChange(e) {
this.props.onChange(e.target.value);
}
render() {
return (
<div>
<select className="Chosen-select" ref={el => this.el = el}>
{this.props.children}
</select>
</div>
);
}
}
Try it on CodePen
Integrating with Other View Libraries
React can be embedded into other applications thanks to the flexibility of ReactDOM.render()
.
Although React is commonly used at startup to load a single root React component into the DOM, ReactDOM.render()
can also be called multiple times for independent parts of the UI which can be as small as a button, or as large as an app.
In fact, this is exactly how React is used at Facebook.
This lets us write applications in React piece by piece, and combine them with our existing server-generated templates and other client-side code.
Replacing String-Based Rendering with React
A common pattern in older web applications is to describe chunks of the DOM as a string and insert it into the DOM like so: $el.html(htmlString)
.
These points in a codebase are perfect for introducing React.
Just rewrite the string based rendering as a React component.
So the following jQuery implementation¡
$('#container').html('<button id="btn">Say Hello</button>');
$('#btn').click(function() {
alert('Hello!');
});
¡could be rewritten using a React component:
function Button() {
return <button id="btn">Say Hello</button>;
}
ReactDOM.render(
<Button />,
document.getElementById('container'),
function() {
$('#btn').click(function() {
alert('Hello!');
});
}
);
From here you could start moving more logic into the component and begin adopting more common React practices.
For example, in components it is best not to rely on IDs because the same component can be rendered multiple times.
Instead, we will use the React event system and register the click handler directly on the React <button>
element:
function Button(props) {
return <button onClick={props.onClick}>Say Hello</button>;}
function HelloButton() {
function handleClick() { alert('Hello!');
}
return <Button onClick={handleClick} />;}
ReactDOM.render(
<HelloButton />,
document.getElementById('container')
);
Try it on CodePen
You can have as many such isolated components as you like, and use ReactDOM.render()
to render them to different DOM containers.
Gradually, as you convert more of your app to React, you will be able to combine them into larger components, and move some of the ReactDOM.render()
calls up the hierarchy.
Embedding React in a Backbone View
Backbone views typically use HTML strings, or string-producing template functions, to create the content for their DOM elements.
This process, too, can be replaced with rendering a React component.
Below, we will create a Backbone view called ParagraphView
.
It will override Backbone's render()
function to render a React <Paragraph>
component into the DOM element provided by Backbone (this.el
).
Here, too, we are using ReactDOM.render()
:
function Paragraph(props) { return <p>{props.text}</p>;
}
const ParagraphView = Backbone.View.extend({ render() {
const text = this.model.get('text');
ReactDOM.render(<Paragraph text={text} />, this.el); return this;
},
remove() {
ReactDOM.unmountComponentAtNode(this.el); Backbone.View.prototype.remove.call(this);
}
});
Try it on CodePen
It is important that we also call ReactDOM.unmountComponentAtNode()
in the remove
method so that React unregisters event handlers and other resources associated with the component tree when it is detached.
When a component is removed from within a React tree, the cleanup is performed automatically, but because we are removing the entire tree by hand, we must call this method.
Integrating with Model Layers
While it is generally recommended to use unidirectional data flow such as React state, Flux, or Redux, React components can use a model layer from other frameworks and libraries.
Using Backbone Models in React Components
The simplest way to consume Backbone models and collections from a React component is to listen to the various change events and manually force an update.
Components responsible for rendering models would listen to 'change'
events, while components responsible for rendering collections would listen for 'add'
and 'remove'
events.
In both cases, call this.forceUpdate()
to rerender the component with the new data.
In the example below, the List
component renders a Backbone collection, using the Item
component to render individual items.
class Item extends React.Component { constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange() { this.forceUpdate(); }
componentDidMount() {
this.props.model.on('change', this.handleChange); }
componentWillUnmount() {
this.props.model.off('change', this.handleChange); }
render() {
return <li>{this.props.model.get('text')}</li>;
}
}
class List extends React.Component { constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange() { this.forceUpdate(); }
componentDidMount() {
this.props.collection.on('add', 'remove', this.handleChange); }
componentWillUnmount() {
this.props.collection.off('add', 'remove', this.handleChange); }
render() {
return (
<ul>
{this.props.collection.map(model => (
<Item key={model.cid} model={model} /> ))}
</ul>
);
}
}
Try it on CodePen
Extracting Data from Backbone Models
The approach above requires your React components to be aware of the Backbone models and collections.
If you later plan to migrate to another data management solution, you might want to concentrate the knowledge about Backbone in as few parts of the code as possible.
One solution to this is to extract the model's attributes as plain data whenever it changes, and keep this logic in a single place.
The following is a higher-order component that extracts all attributes of a Backbone model into state, passing the data to the wrapped component.
This way, only the higher-order component needs to know about Backbone model internals, and most components in the app can stay agnostic of Backbone.
In the example below, we will make a copy of the model's attributes to form the initial state.
We subscribe to the change
event (and unsubscribe on unmounting), and when it happens, we update the state with the model's current attributes.
Finally, we make sure that if the model
prop itself changes, we don't forget to unsubscribe from the old model, and subscribe to the new one.
Note that this example is not meant to be exhaustive with regards to working with Backbone, but it should give you an idea for how to approach this in a generic way:
function connectToBackboneModel(WrappedComponent) { return class BackboneComponent extends React.Component {
constructor(props) {
super(props);
this.state = Object.assign({}, props.model.attributes); this.handleChange = this.handleChange.bind(this);
}
componentDidMount() {
this.props.model.on('change', this.handleChange); }
componentWillReceiveProps(nextProps) {
this.setState(Object.assign({}, nextProps.model.attributes)); if (nextProps.model !== this.props.model) {
this.props.model.off('change', this.handleChange); nextProps.model.on('change', this.handleChange); }
}
componentWillUnmount() {
this.props.model.off('change', this.handleChange); }
handleChange(model) {
this.setState(model.changedAttributes()); }
render() {
const propsExceptModel = Object.assign({}, this.props);
delete propsExceptModel.model;
return <WrappedComponent {...propsExceptModel} {...this.state} />; }
}
}
To demonstrate how to use it, we will connect a NameInput
React component to a Backbone model, and update its firstName
attribute every time the input changes:
function NameInput(props) {
return (
<p>
<input value={props.firstName} onChange={props.handleChange} /> <br />
My name is {props.firstName}.
</p>
);
}
const BackboneNameInput = connectToBackboneModel(NameInput);
function Example(props) {
function handleChange(e) {
props.model.set('firstName', e.target.value); }
return (
<BackboneNameInput model={props.model} handleChange={handleChange} />
);
}
const model = new Backbone.Model({ firstName: 'Frodo' });
ReactDOM.render(
<Example model={model} />,
document.getElementById('root')
);
Try it on CodePen
This technique is not limited to Backbone.
You can use React with any model library by subscribing to its changes in the lifecycle methods and, optionally, copying the data into the local React state.
JSX In Depth
Fundamentally, JSX just provides syntactic sugar for the React.createElement(component, props, ...children)
function.
The JSX code:
<MyButton color="blue" shadowSize={2}>
Click Me
</MyButton>
compiles into:
React.createElement(
MyButton,
{color: 'blue', shadowSize: 2},
'Click Me'
)
You can also use the self-closing form of the tag if there are no children.
So:
<div className="sidebar" />
compiles into:
React.createElement(
'div',
{className: 'sidebar'}
)
If you want to test out how some specific JSX is converted into JavaScript, you can try out the online Babel compiler.
Specifying The React Element Type
The first part of a JSX tag determines the type of the React element.
Capitalized types indicate that the JSX tag is referring to a React component.
These tags get compiled into a direct reference to the named variable, so if you use the JSX <Foo />
expression, Foo
must be in scope.
React Must Be in Scope
Since JSX compiles into calls to React.createElement
, the React
library must also always be in scope from your JSX code.
For example, both of the imports are necessary in this code, even though React
and CustomButton
are not directly referenced from JavaScript:
import React from 'react';import CustomButton from './CustomButton';
function WarningButton() {
// return React.createElement(CustomButton, {color: 'red'}, null); return <CustomButton color="red" />;
}
If you don't use a JavaScript bundler and loaded React from a <script>
tag, it is already in scope as the React
global.
Using Dot Notation for JSX Type
You can also refer to a React component using dot-notation from within JSX.
This is convenient if you have a single module that exports many React components.
For example, if MyComponents.DatePicker
is a component, you can use it directly from JSX with:
import React from 'react';
const MyComponents = {
DatePicker: function DatePicker(props) {
return <div>Imagine a {props.color} datepicker here.</div>;
}
}
function BlueDatePicker() {
return <MyComponents.DatePicker color="blue" />;}
User-Defined Components Must Be Capitalized
When an element type starts with a lowercase letter, it refers to a built-in component like <div>
or <span>
and results in a string 'div'
or 'span'
passed to React.createElement
.
Types that start with a capital letter like <Foo />
compile to React.createElement(Foo)
and correspond to a component defined or imported in your JavaScript file.
We recommend naming components with a capital letter.
If you do have a component that starts with a lowercase letter, assign it to a capitalized variable before using it in JSX.
For example, this code will not run as expected:
import React from 'react';
// Wrong! This is a component and should have been capitalized:function hello(props) { // Correct! This use of <div> is legitimate because div is a valid HTML tag:
return <div>Hello {props.toWhat}</div>;
}
function HelloWorld() {
// Wrong! React thinks <hello /> is an HTML tag because it's not capitalized: return <hello toWhat="World" />;}
To fix this, we will rename hello
to Hello
and use <Hello />
when referring to it:
import React from 'react';
// Correct! This is a component and should be capitalized:function Hello(props) { // Correct! This use of <div> is legitimate because div is a valid HTML tag:
return <div>Hello {props.toWhat}</div>;
}
function HelloWorld() {
// Correct! React knows <Hello /> is a component because it's capitalized.
return <Hello toWhat="World" />;}
Choosing the Type at Runtime
You cannot use a general expression as the React element type.
If you do want to use a general expression to indicate the type of the element, just assign it to a capitalized variable first.
This often comes up when you want to render a different component based on a prop:
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Wrong! JSX type can't be an expression.
return <components[props.storyType] story={props.story} />;}
To fix this, we will assign the type to a capitalized variable first:
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Correct! JSX type can be a capitalized variable.
const SpecificStory = components[props.storyType]; return <SpecificStory story={props.story} />;}
Props in JSX
There are several different ways to specify props in JSX.
JavaScript Expressions as Props
You can pass any JavaScript expression as a prop, by surrounding it with {}
.
For example, in this JSX:
<MyComponent foo={1 + 2 + 3 + 4} />
For MyComponent
, the value of props.foo
will be 10
because the expression 1 + 2 + 3 + 4
gets evaluated.
if
statements and for
loops are not expressions in JavaScript, so they can't be used in JSX directly.
Instead, you can put these in the surrounding code.
For example:
function NumberDescriber(props) {
let description;
if (props.number % 2 == 0) { description = <strong>even</strong>; } else { description = <i>odd</i>; } return <div>{props.number} is an {description} number</div>;
}
You can learn more about conditional rendering and loops in the corresponding sections.
String Literals
You can pass a string literal as a prop.
These two JSX expressions are equivalent:
<MyComponent message="hello world" />
<MyComponent message={'hello world'} />
When you pass a string literal, its value is HTML-unescaped.
So these two JSX expressions are equivalent:
<MyComponent message="<3" />
<MyComponent message={'<3'} />
This behavior is usually not relevant.
It's only mentioned here for completeness.
Props Default to ¡°True¡±
If you pass no value for a prop, it defaults to true
.
These two JSX expressions are equivalent:
<MyTextBox autocomplete />
<MyTextBox autocomplete={true} />
In general, we don't recommend not passing a value for a prop, because it can be confused with the ES6 object shorthand {foo}
which is short for {foo: foo}
rather than {foo: true}
.
This behavior is just there so that it matches the behavior of HTML.
Spread Attributes
If you already have props
as an object, and you want to pass it in JSX, you can use ...
as a ¡°spread¡± operator to pass the whole props object.
These two components are equivalent:
function App1() {
return <Greeting firstName="Ben" lastName="Hector" />;
}
function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;}
You can also pick specific props that your component will consume while passing all other props using the spread operator.
const Button = props => {
const { kind, ...other } = props; const className = kind === "primary" ? "PrimaryButton" : "SecondaryButton";
return <button className={className} {...other} />;
};
const App = () => {
return (
<div>
<Button kind="primary" onClick={() => console.log("clicked!")}>
Hello World!
</Button>
</div>
);
};
In the example above, the kind
prop is safely consumed and is not passed on to the <button>
element in the DOM.
All other props are passed via the ...other
object making this component really flexible.
You can see that it passes an onClick
and children
props.
Spread attributes can be useful but they also make it easy to pass unnecessary props to components that don't care about them or to pass invalid HTML attributes to the DOM.
We recommend using this syntax sparingly.
Children in JSX
In JSX expressions that contain both an opening tag and a closing tag, the content between those tags is passed as a special prop: props.children
.
There are several different ways to pass children:
String Literals
You can put a string between the opening and closing tags and props.children
will just be that string.
This is useful for many of the built-in HTML elements.
For example:
<MyComponent>Hello world!</MyComponent>
This is valid JSX, and props.children
in MyComponent
will simply be the string "Hello world!"
.
HTML is unescaped, so you can generally write JSX just like you would write HTML in this way:
<div>This is valid HTML & JSX at the same time.</div>
JSX removes whitespace at the beginning and ending of a line.
It also removes blank lines.
New lines adjacent to tags are removed; new lines that occur in the middle of string literals are condensed into a single space.
So these all render to the same thing:
<div>Hello World</div>
<div>
Hello World
</div>
<div>
Hello
World
</div>
<div>
Hello World
</div>
JSX Children
You can provide more JSX elements as the children.
This is useful for displaying nested components:
<MyContainer>
<MyFirstComponent />
<MySecondComponent />
</MyContainer>
You can mix together different types of children, so you can use string literals together with JSX children.
This is another way in which JSX is like HTML, so that this is both valid JSX and valid HTML:
<div>
Here is a list:
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
</div>
A React component can also return an array of elements:
render() {
// No need to wrap list items in an extra element!
return [
// Don't forget the keys :)
<li key="A">First item</li>,
<li key="B">Second item</li>,
<li key="C">Third item</li>,
];
}
JavaScript Expressions as Children
You can pass any JavaScript expression as children, by enclosing it within {}
.
For example, these expressions are equivalent:
<MyComponent>foo</MyComponent>
<MyComponent>{'foo'}</MyComponent>
This is often useful for rendering a list of JSX expressions of arbitrary length.
For example, this renders an HTML list:
function Item(props) {
return <li>{props.message}</li>;}
function TodoList() {
const todos = ['finish doc', 'submit pr', 'nag dan to review'];
return (
<ul>
{todos.map((message) => <Item key={message} message={message} />)} </ul>
);
}
JavaScript expressions can be mixed with other types of children.
This is often useful in lieu of string templates:
function Hello(props) {
return <div>Hello {props.addressee}!</div>;}
Functions as Children
Normally, JavaScript expressions inserted in JSX will evaluate to a string, a React element, or a list of those things.
However, props.children
works just like any other prop in that it can pass any sort of data, not just the sorts that React knows how to render.
For example, if you have a custom component, you could have it take a callback as props.children
:
// Calls the children callback numTimes to produce a repeated component
function Repeat(props) {
let items = [];
for (let i = 0; i < props.numTimes; i++) { items.push(props.children(i));
}
return <div>{items}</div>;
}
function ListOfTenThings() {
return (
<Repeat numTimes={10}>
{(index) => <div key={index}>This is item {index} in the list</div>} </Repeat>
);
}
Children passed to a custom component can be anything, as long as that component transforms them into something React can understand before rendering.
This usage is not common, but it works if you want to stretch what JSX is capable of.
Booleans, Null, and Undefined Are Ignored
false
, null
, undefined
, and true
are valid children.
They simply don't render.
These JSX expressions will all render to the same thing:
<div />
<div></div>
<div>{false}</div>
<div>{null}</div>
<div>{undefined}</div>
<div>{true}</div>
This can be useful to conditionally render React elements.
This JSX renders the <Header />
component only if showHeader
is true
:
<div>
{showHeader && <Header />} <Content />
</div>
One caveat is that some ¡°falsy¡± values, such as the 0
number, are still rendered by React.
For example, this code will not behave as you might expect because 0
will be printed when props.messages
is an empty array:
<div>
{props.messages.length && <MessageList messages={props.messages} />
}
</div>
To fix this, make sure that the expression before &&
is always boolean:
<div>
{props.messages.length > 0 && <MessageList messages={props.messages} />
}
</div>
Conversely, if you want a value like false
, true
, null
, or undefined
to appear in the output, you have to convert it to a string first:
<div>
My JavaScript variable is {String(myVariable)}.</div>
Optimizing Performance
Internally, React uses several clever techniques to minimize the number of costly DOM operations required to update the UI.
For many applications, using React will lead to a fast user interface without doing much work to specifically optimize for performance.
Nevertheless, there are several ways you can speed up your React application.
Use the Production Build
If you're benchmarking or experiencing performance problems in your React apps, make sure you're testing with the minified production build.
By default, React includes many helpful warnings.
These warnings are very useful in development.
However, they make React larger and slower so you should make sure to use the production version when you deploy the app.
If you aren't sure whether your build process is set up correctly, you can check it by installing React Developer Tools for Chrome.
If you visit a site with React in production mode, the icon will have a dark background:
If you visit a site with React in development mode, the icon will have a red background:
It is expected that you use the development mode when working on your app, and the production mode when deploying your app to the users.
You can find instructions for building your app for production below.
Create React App
If your project is built with Create React App, run:
npm run build
This will create a production build of your app in the build/
folder of your project.
Remember that this is only necessary before deploying to production.
For normal development, use npm start
.
Single-File Builds
We offer production-ready versions of React and React DOM as single files:
<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
Remember that only React files ending with .production.min.js
are suitable for production.
Brunch
For the most efficient Brunch production build, install the terser-brunch
plugin:
# If you use npm
npm install --save-dev terser-brunch
# If you use Yarn
yarn add --dev terser-brunch
Then, to create a production build, add the -p
flag to the build
command:
brunch build -p
Remember that you only need to do this for production builds.
You shouldn't pass the -p
flag or apply this plugin in development, because it will hide useful React warnings and make the builds much slower.
Browserify
For the most efficient Browserify production build, install a few plugins:
# If you use npm
npm install --save-dev envify terser uglifyify
# If you use Yarn
yarn add --dev envify terser uglifyify
To create a production build, make sure that you add these transforms (the order matters):
- The
envify
transform ensures the right build environment is set.
Make it global (-g
).
- The
uglifyify
transform removes development imports.
Make it global too (-g
).
- Finally, the resulting bundle is piped to
terser
for mangling (read why).
For example:
browserify ./index.js \
-g [ envify --NODE_ENV production ] \
-g uglifyify \
| terser --compress --mangle > ./bundle.js
Remember that you only need to do this for production builds.
You shouldn't apply these plugins in development because they will hide useful React warnings, and make the builds much slower.
Rollup
For the most efficient Rollup production build, install a few plugins:
# If you use npm
npm install --save-dev rollup-plugin-commonjs rollup-plugin-replace rollup-plugin-terser
# If you use Yarn
yarn add --dev rollup-plugin-commonjs rollup-plugin-replace rollup-plugin-terser
To create a production build, make sure that you add these plugins (the order matters):
- The
replace
plugin ensures the right build environment is set.
- The
commonjs
plugin provides support for CommonJS in Rollup.
- The
terser
plugin compresses and mangles the final bundle.
plugins: [
// ...
require('rollup-plugin-replace')({
'process.env.NODE_ENV': JSON.stringify('production')
}),
require('rollup-plugin-commonjs')(),
require('rollup-plugin-terser')(),
// ...
]
For a complete setup example see this gist.
Remember that you only need to do this for production builds.
You shouldn't apply the terser
plugin or the replace
plugin with 'production'
value in development because they will hide useful React warnings, and make the builds much slower.
webpack
Note:
If you're using Create React App, please follow the instructions above.
This section is only relevant if you configure webpack directly.
Webpack v4+ will minify your code by default in production mode.
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
mode: 'production',
optimization: {
minimizer: [new TerserPlugin({ /* additional options here */ })],
},
};
You can learn more about this in webpack documentation.
Remember that you only need to do this for production builds.
You shouldn't apply TerserPlugin
in development because it will hide useful React warnings, and make the builds much slower.
Profiling Components with the Chrome Performance Tab
In the development mode, you can visualize how components mount, update, and unmount, using the performance tools in supported browsers.
For example:
To do this in Chrome:
- Temporarily disable all Chrome extensions, especially React DevTools.
They can significantly skew the results!
- Make sure you're running the application in the development mode.
- Open the Chrome DevTools Performance tab and press Record.
- Perform the actions you want to profile.
Don't record more than 20 seconds or Chrome might hang.
- Stop recording.
- React events will be grouped under the User Timing label.
For a more detailed walkthrough, check out this article by Ben Schwarz.
Note that the numbers are relative so components will render faster in production.
Still, this should help you realize when unrelated UI gets updated by mistake, and how deep and how often your UI updates occur.
Currently Chrome, Edge, and IE are the only browsers supporting this feature, but we use the standard User Timing API so we expect more browsers to add support for it.
Profiling Components with the DevTools Profiler
react-dom
16.5+ and react-native
0.57+ provide enhanced profiling capabilities in DEV mode with the React DevTools Profiler.
An overview of the Profiler can be found in the blog post ¡°Introducing the React Profiler¡±.
A video walkthrough of the profiler is also available on YouTube.
If you haven't yet installed the React DevTools, you can find them here:
- Chrome Browser Extension
- Firefox Browser Extension
- Standalone Node Package
Note
A production profiling bundle of react-dom
is also available as react-dom/profiling
.
Read more about how to use this bundle at fb.me/react-profiling
Virtualize Long Lists
If your application renders long lists of data (hundreds or thousands of rows), we recommended using a technique known as ¡°windowing¡±.
This technique only renders a small subset of your rows at any given time, and can dramatically reduce the time it takes to re-render the components as well as the number of DOM nodes created.
react-window and react-virtualized are popular windowing libraries.
They provide several reusable components for displaying lists, grids, and tabular data.
You can also create your own windowing component, like Twitter did, if you want something more tailored to your application's specific use case.
Avoid Reconciliation
React builds and maintains an internal representation of the rendered UI.
It includes the React elements you return from your components.
This representation lets React avoid creating DOM nodes and accessing existing ones beyond necessity, as that can be slower than operations on JavaScript objects.
Sometimes it is referred to as a ¡°virtual DOM¡±, but it works the same way on React Native.
When a component's props or state change, React decides whether an actual DOM update is necessary by comparing the newly returned element with the previously rendered one.
When they are not equal, React will update the DOM.
Even though React only updates the changed DOM nodes, re-rendering still takes some time.
In many cases it's not a problem, but if the slowdown is noticeable, you can speed all of this up by overriding the lifecycle function shouldComponentUpdate
, which is triggered before the re-rendering process starts.
The default implementation of this function returns true
, leaving React to perform the update:
shouldComponentUpdate(nextProps, nextState) {
return true;
}
If you know that in some situations your component doesn't need to update, you can return false
from shouldComponentUpdate
instead, to skip the whole rendering process, including calling render()
on this component and below.
In most cases, instead of writing shouldComponentUpdate()
by hand, you can inherit from React.PureComponent
.
It is equivalent to implementing shouldComponentUpdate()
with a shallow comparison of current and previous props and state.
shouldComponentUpdate In Action
Here's a subtree of components.
For each one, SCU
indicates what shouldComponentUpdate
returned, and vDOMEq
indicates whether the rendered React elements were equivalent.
Finally, the circle's color indicates whether the component had to be reconciled or not.
Since shouldComponentUpdate
returned false
for the subtree rooted at C2, React did not attempt to render C2, and thus didn't even have to invoke shouldComponentUpdate
on C4 and C5.
For C1 and C3, shouldComponentUpdate
returned true
, so React had to go down to the leaves and check them.
For C6 shouldComponentUpdate
returned true
, and since the rendered elements weren't equivalent React had to update the DOM.
The last interesting case is C8.
React had to render this component, but since the React elements it returned were equal to the previously rendered ones, it didn't have to update the DOM.
Note that React only had to do DOM mutations for C6, which was inevitable.
For C8, it bailed out by comparing the rendered React elements, and for C2's subtree and C7, it didn't even have to compare the elements as we bailed out on shouldComponentUpdate
, and render
was not called.
Examples
If the only way your component ever changes is when the props.color
or the state.count
variable changes, you could have shouldComponentUpdate
check that:
class CounterButton extends React.Component {
constructor(props) {
super(props);
this.state = {count: 1};
}
shouldComponentUpdate(nextProps, nextState) {
if (this.props.color !== nextProps.color) {
return true;
}
if (this.state.count !== nextState.count) {
return true;
}
return false;
}
render() {
return (
<button
color={this.props.color}
onClick={() => this.setState(state => ({count: state.count + 1}))}>
Count: {this.state.count}
</button>
);
}
}
In this code, shouldComponentUpdate
is just checking if there is any change in props.color
or state.count
.
If those values don't change, the component doesn't update.
If your component got more complex, you could use a similar pattern of doing a ¡°shallow comparison¡± between all the fields of props
and state
to determine if the component should update.
This pattern is common enough that React provides a helper to use this logic - just inherit from React.PureComponent
.
So this code is a simpler way to achieve the same thing:
class CounterButton extends React.PureComponent {
constructor(props) {
super(props);
this.state = {count: 1};
}
render() {
return (
<button
color={this.props.color}
onClick={() => this.setState(state => ({count: state.count + 1}))}>
Count: {this.state.count}
</button>
);
}
}
Most of the time, you can use React.PureComponent
instead of writing your own shouldComponentUpdate
.
It only does a shallow comparison, so you can't use it if the props or state may have been mutated in a way that a shallow comparison would miss.
This can be a problem with more complex data structures.
For example, let's say you want a ListOfWords
component to render a comma-separated list of words, with a parent WordAdder
component that lets you click a button to add a word to the list.
This code does not work correctly:
class ListOfWords extends React.PureComponent {
render() {
return <div>{this.props.words.join(',')}</div>;
}
}
class WordAdder extends React.Component {
constructor(props) {
super(props);
this.state = {
words: ['marklar']
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
// This section is bad style and causes a bug
const words = this.state.words;
words.push('marklar');
this.setState({words: words});
}
render() {
return (
<div>
<button onClick={this.handleClick} />
<ListOfWords words={this.state.words} />
</div>
);
}
}
The problem is that PureComponent
will do a simple comparison between the old and new values of this.props.words
.
Since this code mutates the words
array in the handleClick
method of WordAdder
, the old and new values of this.props.words
will compare as equal, even though the actual words in the array have changed.
The ListOfWords
will thus not update even though it has new words that should be rendered.
The Power Of Not Mutating Data
The simplest way to avoid this problem is to avoid mutating values that you are using as props or state.
For example, the handleClick
method above could be rewritten using concat
as:
handleClick() {
this.setState(state => ({
words: state.words.concat(['marklar'])
}));
}
ES6 supports a spread syntax for arrays which can make this easier.
If you're using Create React App, this syntax is available by default.
handleClick() {
this.setState(state => ({
words: [...state.words, 'marklar'],
}));
};
You can also rewrite code that mutates objects to avoid mutation, in a similar way.
For example, let's say we have an object named colormap
and we want to write a function that changes colormap.right
to be 'blue'
.
We could write:
function updateColorMap(colormap) {
colormap.right = 'blue';
}
To write this without mutating the original object, we can use Object.assign method:
function updateColorMap(colormap) {
return Object.assign({}, colormap, {right: 'blue'});
}
updateColorMap
now returns a new object, rather than mutating the old one.
Object.assign
is in ES6 and requires a polyfill.
Object spread syntax makes it easier to update objects without mutation as well:
function updateColorMap(colormap) {
return {...colormap, right: 'blue'};
}
This feature was added to JavaScript in ES2018.
If you're using Create React App, both Object.assign
and the object spread syntax are available by default.
When you deal with deeply nested objects, updating them in an immutable way can feel convoluted.
If you run into this problem, check out Immer or immutability-helper.
These libraries let you write highly readable code without losing the benefits of immutability.
Portals
Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.
ReactDOM.createPortal(child, container)
The first argument (child
) is any renderable React child, such as an element, string, or fragment.
The second argument (container
) is a DOM element.
Usage
Normally, when you return an element from a component's render method, it's mounted into the DOM as a child of the nearest parent node:
render() {
// React mounts a new div and renders the children into it
return (
<div> {this.props.children}
</div> );
}
However, sometimes it's useful to insert a child into a different location in the DOM:
render() {
// React does *not* create a new div.
It renders the children into `domNode`.
// `domNode` is any valid DOM node, regardless of its location in the DOM.
return ReactDOM.createPortal(
this.props.children,
domNode );
}
A typical use case for portals is when a parent component has an overflow: hidden
or z-index
style, but you need the child to visually ¡°break out¡± of its container.
For example, dialogs, hovercards, and tooltips.
Note:
When working with portals, remember that managing keyboard focus becomes very important.
For modal dialogs, ensure that everyone can interact with them by following the WAI-ARIA Modal Authoring Practices.
Try it on CodePen
Event Bubbling Through Portals
Even though a portal can be anywhere in the DOM tree, it behaves like a normal React child in every other way.
Features like context work exactly the same regardless of whether the child is a portal, as the portal still exists in the React tree regardless of position in the DOM tree.
This includes event bubbling.
An event fired from inside a portal will propagate to ancestors in the containing React tree, even if those elements are not ancestors in the DOM tree.
Assuming the following HTML structure:
<html>
<body>
<div id="app-root"></div>
<div id="modal-root"></div>
</body>
</html>
A Parent
component in #app-root
would be able to catch an uncaught, bubbling event from the sibling node #modal-root
.
// These two containers are siblings in the DOM
const appRoot = document.getElementById('app-root');
const modalRoot = document.getElementById('modal-root');
class Modal extends React.Component {
constructor(props) {
super(props);
this.el = document.createElement('div');
}
componentDidMount() {
// The portal element is inserted in the DOM tree after
// the Modal's children are mounted, meaning that children
// will be mounted on a detached DOM node.
If a child
// component requires to be attached to the DOM tree
// immediately when mounted, for example to measure a
// DOM node, or uses 'autoFocus' in a descendant, add
// state to Modal and only render the children when Modal
// is inserted in the DOM tree.
modalRoot.appendChild(this.el);
}
componentWillUnmount() {
modalRoot.removeChild(this.el);
}
render() {
return ReactDOM.createPortal( this.props.children, this.el ); }
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {clicks: 0};
this.handleClick = this.handleClick.bind(this);
}
handleClick() { // This will fire when the button in Child is clicked, // updating Parent's state, even though button // is not direct descendant in the DOM.
this.setState(state => ({ clicks: state.clicks + 1 })); }
render() {
return (
<div onClick={this.handleClick}> <p>Number of clicks: {this.state.clicks}</p>
<p>
Open up the browser DevTools
to observe that the button
is not a child of the div
with the onClick handler.
</p>
<Modal> <Child /> </Modal> </div>
);
}
}
function Child() {
// The click event on this button will bubble up to parent, // because there is no 'onClick' attribute defined return (
<div className="modal">
<button>Click</button> </div>
);
}
ReactDOM.render(<Parent />, appRoot);
Try it on CodePen
Catching an event bubbling up from a portal in a parent component allows the development of more flexible abstractions that are not inherently reliant on portals.
For example, if you render a <Modal />
component, the parent can capture its events regardless of whether it's implemented using portals.
Profiler API
The Profiler
measures how often a React application renders and what the ¡°cost¡± of rendering is.
Its purpose is to help identify parts of an application that are slow and may benefit from optimizations such as memoization.
Note:
Profiling adds some additional overhead, so it is disabled in the production build.
To opt into production profiling, React provides a special production build with profiling enabled.
Read more about how to use this build at fb.me/react-profiling
Usage
A Profiler
can be added anywhere in a React tree to measure the cost of rendering that part of the tree.
It requires two props: an id
(string) and an onRender
callback (function) which React calls any time a component within the tree ¡°commits¡± an update.
For example, to profile a Navigation
component and its descendants:
render(
<App>
<Profiler id="Navigation" onRender={callback}> <Navigation {...props} />
</Profiler>
<Main {...props} />
</App>
);
Multiple Profiler
components can be used to measure different parts of an application:
render(
<App>
<Profiler id="Navigation" onRender={callback}> <Navigation {...props} />
</Profiler>
<Profiler id="Main" onRender={callback}> <Main {...props} />
</Profiler>
</App>
);
Profiler
components can also be nested to measure different components within the same subtree:
render(
<App>
<Profiler id="Panel" onRender={callback}> <Panel {...props}>
<Profiler id="Content" onRender={callback}> <Content {...props} />
</Profiler>
<Profiler id="PreviewPane" onRender={callback}> <PreviewPane {...props} />
</Profiler>
</Panel>
</Profiler>
</App>
);
Note
Although Profiler
is a light-weight component, it should be used only when necessary; each use adds some CPU and memory overhead to an application.
onRender
Callback
The Profiler
requires an onRender
function as a prop.
React calls this function any time a component within the profiled tree ¡°commits¡± an update.
It receives parameters describing what was rendered and how long it took.
function onRenderCallback(
id, // the "id" prop of the Profiler tree that has just committed
phase, // either "mount" (if the tree just mounted) or "update" (if it re-rendered)
actualDuration, // time spent rendering the committed update
baseDuration, // estimated time to render the entire subtree without memoization
startTime, // when React began rendering this update
commitTime, // when React committed this update
interactions // the Set of interactions belonging to this update
) {
// Aggregate or log render timings...
}
Let's take a closer look at each of the props:
-
id: string
-
The id
prop of the Profiler
tree that has just committed.
This can be used to identify which part of the tree was committed if you are using multiple profilers.
-
phase: "mount" | "update"
-
Identifies whether the tree has just been mounted for the first time or re-rendered due to a change in props, state, or hooks.
-
actualDuration: number
-
Time spent rendering the Profiler
and its descendants for the current update.
This indicates how well the subtree makes use of memoization (e.g.
React.memo
, useMemo
, shouldComponentUpdate
).
Ideally this value should decrease significantly after the initial mount as many of the descendants will only need to re-render if their specific props change.
-
baseDuration: number
-
Duration of the most recent render
time for each individual component within the Profiler
tree.
This value estimates a worst-case cost of rendering (e.g.
the initial mount or a tree with no memoization).
-
startTime: number
-
Timestamp when React began rendering the current update.
-
commitTime: number
-
Timestamp when React committed the current update.
This value is shared between all profilers in a commit, enabling them to be grouped if desirable.
-
interactions: Set
-
Set of ¡°interactions¡± that were being traced when the update was scheduled (e.g.
when render
or setState
were called).
Note
Interactions can be used to identify the cause of an update, although the API for tracing them is still experimental.
Learn more about it at fb.me/react-interaction-tracing
React Without ES6
Normally you would define a React component as a plain JavaScript class:
class Greeting extends React.Component {
render() {
return <h2>Hello, {this.props.name}</h2>;
}
}
If you don't use ES6 yet, you may use the create-react-class
module instead:
var createReactClass = require('create-react-class');
var Greeting = createReactClass({
render: function() {
return <h2>Hello, {this.props.name}</h2>;
}
});
The API of ES6 classes is similar to createReactClass()
with a few exceptions.
Declaring Default Props
With functions and ES6 classes defaultProps
is defined as a property on the component itself:
class Greeting extends React.Component {
// ...
}
Greeting.defaultProps = {
name: 'Mary'
};
With createReactClass()
, you need to define getDefaultProps()
as a function on the passed object:
var Greeting = createReactClass({
getDefaultProps: function() {
return {
name: 'Mary'
};
},
// ...
});
Setting the Initial State
In ES6 classes, you can define the initial state by assigning this.state
in the constructor:
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {count: props.initialCount};
}
// ...
}
With createReactClass()
, you have to provide a separate getInitialState
method that returns the initial state:
var Counter = createReactClass({
getInitialState: function() {
return {count: this.props.initialCount};
},
// ...
});
Autobinding
In React components declared as ES6 classes, methods follow the same semantics as regular ES6 classes.
This means that they don't automatically bind this
to the instance.
You'll have to explicitly use .bind(this)
in the constructor:
class SayHello extends React.Component {
constructor(props) {
super(props);
this.state = {message: 'Hello!'};
// This line is important!
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
alert(this.state.message);
}
render() {
// Because `this.handleClick` is bound, we can use it as an event handler.
return (
<button onClick={this.handleClick}>
Say hello
</button>
);
}
}
With createReactClass()
, this is not necessary because it binds all methods:
var SayHello = createReactClass({
getInitialState: function() {
return {message: 'Hello!'};
},
handleClick: function() {
alert(this.state.message);
},
render: function() {
return (
<button onClick={this.handleClick}>
Say hello
</button>
);
}
});
This means writing ES6 classes comes with a little more boilerplate code for event handlers, but the upside is slightly better performance in large applications.
If the boilerplate code is too unattractive to you, you may enable the experimental Class Properties syntax proposal with Babel:
class SayHello extends React.Component {
constructor(props) {
super(props);
this.state = {message: 'Hello!'};
}
// WARNING: this syntax is experimental!
// Using an arrow here binds the method:
handleClick = () => {
alert(this.state.message);
}
render() {
return (
<button onClick={this.handleClick}>
Say hello
</button>
);
}
}
Please note that the syntax above is experimental and the syntax may change, or the proposal might not make it into the language.
If you'd rather play it safe, you have a few options:
- Bind methods in the constructor.
- Use arrow functions, e.g.
onClick={(e) => this.handleClick(e)}
.
- Keep using
createReactClass
.
Mixins
Note:
ES6 launched without any mixin support.
Therefore, there is no support for mixins when you use React with ES6 classes.
We also found numerous issues in codebases using mixins, and don't recommend using them in the new code.
This section exists only for the reference.
Sometimes very different components may share some common functionality.
These are sometimes called cross-cutting concerns.
createReactClass
lets you use a legacy mixins
system for that.
One common use case is a component wanting to update itself on a time interval.
It's easy to use setInterval()
, but it's important to cancel your interval when you don't need it anymore to save memory.
React provides lifecycle methods that let you know when a component is about to be created or destroyed.
Let's create a simple mixin that uses these methods to provide an easy setInterval()
function that will automatically get cleaned up when your component is destroyed.
var SetIntervalMixin = {
componentWillMount: function() {
this.intervals = [];
},
setInterval: function() {
this.intervals.push(setInterval.apply(null, arguments));
},
componentWillUnmount: function() {
this.intervals.forEach(clearInterval);
}
};
var createReactClass = require('create-react-class');
var TickTock = createReactClass({
mixins: [SetIntervalMixin], // Use the mixin
getInitialState: function() {
return {seconds: 0};
},
componentDidMount: function() {
this.setInterval(this.tick, 1000); // Call a method on the mixin
},
tick: function() {
this.setState({seconds: this.state.seconds + 1});
},
render: function() {
return (
<p>
React has been running for {this.state.seconds} seconds.
</p>
);
}
});
ReactDOM.render(
<TickTock />,
document.getElementById('example')
);
If a component is using multiple mixins and several mixins define the same lifecycle method (i.e.
several mixins want to do some cleanup when the component is destroyed), all of the lifecycle methods are guaranteed to be called.
Methods defined on mixins run in the order mixins were listed, followed by a method call on the component.
React Without JSX
JSX is not a requirement for using React.
Using React without JSX is especially convenient when you don't want to set up compilation in your build environment.
Each JSX element is just syntactic sugar for calling React.createElement(component, props, ...children)
.
So, anything you can do with JSX can also be done with just plain JavaScript.
For example, this code written with JSX:
class Hello extends React.Component {
render() {
return <div>Hello {this.props.toWhat}</div>;
}
}
ReactDOM.render(
<Hello toWhat="World" />,
document.getElementById('root')
);
can be compiled to this code that does not use JSX:
class Hello extends React.Component {
render() {
return React.createElement('div', null, `Hello ${this.props.toWhat}`);
}
}
ReactDOM.render(
React.createElement(Hello, {toWhat: 'World'}, null),
document.getElementById('root')
);
If you're curious to see more examples of how JSX is converted to JavaScript, you can try out the online Babel compiler.
The component can either be provided as a string, as a subclass of React.Component
, or a plain function.
If you get tired of typing React.createElement
so much, one common pattern is to assign a shorthand:
const e = React.createElement;
ReactDOM.render(
e('div', null, 'Hello World'),
document.getElementById('root')
);
If you use this shorthand form for React.createElement
, it can be almost as convenient to use React without JSX.
Alternatively, you can refer to community projects such as react-hyperscript
and hyperscript-helpers
which offer a terser syntax.
Reconciliation
React provides a declarative API so that you don't have to worry about exactly what changes on every update.
This makes writing applications a lot easier, but it might not be obvious how this is implemented within React.
This article explains the choices we made in React's ¡°diffing¡± algorithm so that component updates are predictable while being fast enough for high-performance apps.
Motivation
When you use React, at a single point in time you can think of the render()
function as creating a tree of React elements.
On the next state or props update, that render()
function will return a different tree of React elements.
React then needs to figure out how to efficiently update the UI to match the most recent tree.
There are some generic solutions to this algorithmic problem of generating the minimum number of operations to transform one tree into another.
However, the state of the art algorithms have a complexity in the order of O(n3) where n is the number of elements in the tree.
If we used this in React, displaying 1000 elements would require in the order of one billion comparisons.
This is far too expensive.
Instead, React implements a heuristic O(n) algorithm based on two assumptions:
- Two elements of different types will produce different trees.
- The developer can hint at which child elements may be stable across different renders with a
key
prop.
In practice, these assumptions are valid for almost all practical use cases.
The Diffing Algorithm
When diffing two trees, React first compares the two root elements.
The behavior is different depending on the types of the root elements.
Elements Of Different Types
Whenever the root elements have different types, React will tear down the old tree and build the new tree from scratch.
Going from <a>
to <img>
, or from <Article>
to <Comment>
, or from <Button>
to <div>
- any of those will lead to a full rebuild.
When tearing down a tree, old DOM nodes are destroyed.
Component instances receive componentWillUnmount()
.
When building up a new tree, new DOM nodes are inserted into the DOM.
Component instances receive UNSAFE_componentWillMount()
and then componentDidMount()
.
Any state associated with the old tree is lost.
Any components below the root will also get unmounted and have their state destroyed.
For example, when diffing:
<div>
<Counter />
</div>
<span>
<Counter />
</span>
This will destroy the old Counter
and remount a new one.
Note:
These methods are considered legacy and you should avoid them in new code:
UNSAFE_componentWillMount()
DOM Elements Of The Same Type
When comparing two React DOM elements of the same type, React looks at the attributes of both, keeps the same underlying DOM node, and only updates the changed attributes.
For example:
<div className="before" title="stuff" />
<div className="after" title="stuff" />
By comparing these two elements, React knows to only modify the className
on the underlying DOM node.
When updating style
, React also knows to update only the properties that changed.
For example:
<div style={{color: 'red', fontWeight: 'bold'}} />
<div style={{color: 'green', fontWeight: 'bold'}} />
When converting between these two elements, React knows to only modify the color
style, not the fontWeight
.
After handling the DOM node, React then recurses on the children.
Component Elements Of The Same Type
When a component updates, the instance stays the same, so that state is maintained across renders.
React updates the props of the underlying component instance to match the new element, and calls UNSAFE_componentWillReceiveProps()
, UNSAFE_componentWillUpdate()
and componentDidUpdate()
on the underlying instance.
Next, the render()
method is called and the diff algorithm recurses on the previous result and the new result.
Note:
These methods are considered legacy and you should avoid them in new code:
UNSAFE_componentWillUpdate()
UNSAFE_componentWillReceiveProps()
Recursing On Children
By default, when recursing on the children of a DOM node, React just iterates over both lists of children at the same time and generates a mutation whenever there's a difference.
For example, when adding an element at the end of the children, converting between these two trees works well:
<ul>
<li>first</li>
<li>second</li>
</ul>
<ul>
<li>first</li>
<li>second</li>
<li>third</li>
</ul>
React will match the two <li>first</li>
trees, match the two <li>second</li>
trees, and then insert the <li>third</li>
tree.
If you implement it naively, inserting an element at the beginning has worse performance.
For example, converting between these two trees works poorly:
<ul>
<li>Duke</li>
<li>Villanova</li>
</ul>
<ul>
<li>Connecticut</li>
<li>Duke</li>
<li>Villanova</li>
</ul>
React will mutate every child instead of realizing it can keep the <li>Duke</li>
and <li>Villanova</li>
subtrees intact.
This inefficiency can be a problem.
Keys
In order to solve this issue, React supports a key
attribute.
When children have keys, React uses the key to match children in the original tree with children in the subsequent tree.
For example, adding a key
to our inefficient example above can make the tree conversion efficient:
<ul>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
<ul>
<li key="2014">Connecticut</li>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
Now React knows that the element with key '2014'
is the new one, and the elements with the keys '2015'
and '2016'
have just moved.
In practice, finding a key is usually not hard.
The element you are going to display may already have a unique ID, so the key can just come from your data:
<li key={item.id}>{item.name}</li>
When that's not the case, you can add a new ID property to your model or hash some parts of the content to generate a key.
The key only has to be unique among its siblings, not globally unique.
As a last resort, you can pass an item's index in the array as a key.
This can work well if the items are never reordered, but reorders will be slow.
Reorders can also cause issues with component state when indexes are used as keys.
Component instances are updated and reused based on their key.
If the key is an index, moving an item changes it.
As a result, component state for things like uncontrolled inputs can get mixed up and updated in unexpected ways.
Here is an example of the issues that can be caused by using indexes as keys on CodePen, and here is an updated version of the same example showing how not using indexes as keys will fix these reordering, sorting, and prepending issues.
Tradeoffs
It is important to remember that the reconciliation algorithm is an implementation detail.
React could rerender the whole app on every action; the end result would be the same.
Just to be clear, rerender in this context means calling render
for all components, it doesn't mean React will unmount and remount them.
It will only apply the differences following the rules stated in the previous sections.
We are regularly refining the heuristics in order to make common use cases faster.
In the current implementation, you can express the fact that a subtree has been moved amongst its siblings, but you cannot tell that it has moved somewhere else.
The algorithm will rerender that full subtree.
Because React relies on heuristics, if the assumptions behind them are not met, performance will suffer.
- The algorithm will not try to match subtrees of different component types.
If you see yourself alternating between two component types with very similar output, you may want to make it the same type.
In practice, we haven't found this to be an issue.
- Keys should be stable, predictable, and unique.
Unstable keys (like those produced by
Math.random()
) will cause many component instances and DOM nodes to be unnecessarily recreated, which can cause performance degradation and lost state in child components.
Refs and the DOM
Refs provide a way to access DOM nodes or React elements created in the render method.
In the typical React dataflow, props are the only way that parent components interact with their children.
To modify a child, you re-render it with new props.
However, there are a few cases where you need to imperatively modify a child outside of the typical dataflow.
The child to be modified could be an instance of a React component, or it could be a DOM element.
For both of these cases, React provides an escape hatch.
When to Use Refs
There are a few good use cases for refs:
- Managing focus, text selection, or media playback.
- Triggering imperative animations.
- Integrating with third-party DOM libraries.
Avoid using refs for anything that can be done declaratively.
For example, instead of exposing open()
and close()
methods on a Dialog
component, pass an isOpen
prop to it.
Don't Overuse Refs
Your first inclination may be to use refs to ¡°make things happen¡± in your app.
If this is the case, take a moment and think more critically about where state should be owned in the component hierarchy.
Often, it becomes clear that the proper place to ¡°own¡± that state is at a higher level in the hierarchy.
See the Lifting State Up guide for examples of this.
Note
The examples below have been updated to use the React.createRef()
API introduced in React 16.3.
If you are using an earlier release of React, we recommend using callback refs instead.
Creating Refs
Refs are created using React.createRef()
and attached to React elements via the ref
attribute.
Refs are commonly assigned to an instance property when a component is constructed so they can be referenced throughout the component.
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef(); }
render() {
return <div ref={this.myRef} />; }
}
Accessing Refs
When a ref is passed to an element in render
, a reference to the node becomes accessible at the current
attribute of the ref.
const node = this.myRef.current;
The value of the ref differs depending on the type of the node:
- When the
ref
attribute is used on an HTML element, the ref
created in the constructor with React.createRef()
receives the underlying DOM element as its current
property.
- When the
ref
attribute is used on a custom class component, the ref
object receives the mounted instance of the component as its current
.
-
You may not use the
ref
attribute on function components because they don't have instances.
The examples below demonstrate the differences.
Adding a Ref to a DOM Element
This code uses a ref
to store a reference to a DOM node:
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
// create a ref to store the textInput DOM element
this.textInput = React.createRef(); this.focusTextInput = this.focusTextInput.bind(this);
}
focusTextInput() {
// Explicitly focus the text input using the raw DOM API
// Note: we're accessing "current" to get the DOM node
this.textInput.current.focus(); }
render() {
// tell React that we want to associate the <input> ref
// with the `textInput` that we created in the constructor
return (
<div>
<input
type="text"
ref={this.textInput} /> <input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
React will assign the current
property with the DOM element when the component mounts, and assign it back to null
when it unmounts.
ref
updates happen before componentDidMount
or componentDidUpdate
lifecycle methods.
Adding a Ref to a Class Component
If we wanted to wrap the CustomTextInput
above to simulate it being clicked immediately after mounting, we could use a ref to get access to the custom input and call its focusTextInput
method manually:
class AutoFocusTextInput extends React.Component {
constructor(props) {
super(props);
this.textInput = React.createRef(); }
componentDidMount() {
this.textInput.current.focusTextInput(); }
render() {
return (
<CustomTextInput ref={this.textInput} /> );
}
}
Note that this only works if CustomTextInput
is declared as a class:
class CustomTextInput extends React.Component { // ...
}
Refs and Function Components
By default, you may not use the ref
attribute on function components because they don't have instances:
function MyFunctionComponent() { return <input />;
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.textInput = React.createRef(); }
render() {
// This will *not* work!
return (
<MyFunctionComponent ref={this.textInput} /> );
}
}
If you want to allow people to take a ref
to your function component, you can use forwardRef
(possibly in conjunction with useImperativeHandle
), or you can convert the component to a class.
You can, however, use the ref
attribute inside a function component as long as you refer to a DOM element or a class component:
function CustomTextInput(props) {
// textInput must be declared here so the ref can refer to it const textInput = useRef(null);
function handleClick() {
textInput.current.focus(); }
return (
<div>
<input
type="text"
ref={textInput} /> <input
type="button"
value="Focus the text input"
onClick={handleClick}
/>
</div>
);
}
Exposing DOM Refs to Parent Components
In rare cases, you might want to have access to a child's DOM node from a parent component.
This is generally not recommended because it breaks component encapsulation, but it can occasionally be useful for triggering focus or measuring the size or position of a child DOM node.
While you could add a ref to the child component, this is not an ideal solution, as you would only get a component instance rather than a DOM node.
Additionally, this wouldn't work with function components.
If you use React 16.3 or higher, we recommend to use ref forwarding for these cases.
Ref forwarding lets components opt into exposing any child component's ref as their own.
You can find a detailed example of how to expose a child's DOM node to a parent component in the ref forwarding documentation.
If you use React 16.2 or lower, or if you need more flexibility than provided by ref forwarding, you can use this alternative approach and explicitly pass a ref as a differently named prop.
When possible, we advise against exposing DOM nodes, but it can be a useful escape hatch.
Note that this approach requires you to add some code to the child component.
If you have absolutely no control over the child component implementation, your last option is to use findDOMNode()
, but it is discouraged and deprecated in StrictMode
.
Callback Refs
React also supports another way to set refs called ¡°callback refs¡±, which gives more fine-grain control over when refs are set and unset.
Instead of passing a ref
attribute created by createRef()
, you pass a function.
The function receives the React component instance or HTML DOM element as its argument, which can be stored and accessed elsewhere.
The example below implements a common pattern: using the ref
callback to store a reference to a DOM node in an instance property.
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
this.textInput = null;
this.setTextInputRef = element => { this.textInput = element; };
this.focusTextInput = () => { // Focus the text input using the raw DOM API if (this.textInput) this.textInput.focus(); }; }
componentDidMount() {
// autofocus the input on mount
this.focusTextInput(); }
render() {
// Use the `ref` callback to store a reference to the text input DOM
// element in an instance field (for example, this.textInput).
return (
<div>
<input
type="text"
ref={this.setTextInputRef} />
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput} />
</div>
);
}
}
React will call the ref
callback with the DOM element when the component mounts, and call it with null
when it unmounts.
Refs are guaranteed to be up-to-date before componentDidMount
or componentDidUpdate
fires.
You can pass callback refs between components like you can with object refs that were created with React.createRef()
.
function CustomTextInput(props) {
return (
<div>
<input ref={props.inputRef} /> </div>
);
}
class Parent extends React.Component {
render() {
return (
<CustomTextInput
inputRef={el => this.inputElement = el} />
);
}
}
In the example above, Parent
passes its ref callback as an inputRef
prop to the CustomTextInput
, and the CustomTextInput
passes the same function as a special ref
attribute to the <input>
.
As a result, this.inputElement
in Parent
will be set to the DOM node corresponding to the <input>
element in the CustomTextInput
.
Legacy API: String Refs
If you worked with React before, you might be familiar with an older API where the ref
attribute is a string, like "textInput"
, and the DOM node is accessed as this.refs.textInput
.
We advise against it because string refs have some issues, are considered legacy, and are likely to be removed in one of the future releases.
Note
If you're currently using this.refs.textInput
to access refs, we recommend using either the callback pattern or the createRef
API instead.
Caveats with callback refs
If the ref
callback is defined as an inline function, it will get called twice during updates, first with null
and then again with the DOM element.
This is because a new instance of the function is created with each render, so React needs to clear the old ref and set up the new one.
You can avoid this by defining the ref
callback as a bound method on the class, but note that it shouldn't matter in most cases.
Render Props
The term ¡°render prop¡± refers to a technique for sharing code between React components using a prop whose value is a function.
A component with a render prop takes a function that returns a React element and calls it instead of implementing its own render logic.
<DataProvider render={data => (
<h2>Hello {data.target}</h2>
)}/>
Libraries that use render props include React Router, Downshift and Formik.
In this document, we'll discuss why render props are useful, and how to write your own.
Use Render Props for Cross-Cutting Concerns
Components are the primary unit of code reuse in React, but it's not always obvious how to share the state or behavior that one component encapsulates to other components that need that same state.
For example, the following component tracks the mouse position in a web app:
class MouseTracker extends React.Component {
constructor(props) {
super(props);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.state = { x: 0, y: 0 };
}
handleMouseMove(event) {
this.setState({
x: event.clientX,
y: event.clientY
});
}
render() {
return (
<div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}>
<h2>Move the mouse around!</h2>
<p>The current mouse position is ({this.state.x}, {this.state.y})</p>
</div>
);
}
}
As the cursor moves around the screen, the component displays its (x, y) coordinates in a <p>
.
Now the question is: How can we reuse this behavior in another component? In other words, if another component needs to know about the cursor position, can we encapsulate that behavior so that we can easily share it with that component?
Since components are the basic unit of code reuse in React, let's try refactoring the code a bit to use a <Mouse>
component that encapsulates the behavior we need to reuse elsewhere.
// The <Mouse> component encapsulates the behavior we need...
class Mouse extends React.Component {
constructor(props) {
super(props);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.state = { x: 0, y: 0 };
}
handleMouseMove(event) {
this.setState({
x: event.clientX,
y: event.clientY
});
}
render() {
return (
<div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}>
{/* ...but how do we render something other than a <p>? */}
<p>The current mouse position is ({this.state.x}, {this.state.y})</p>
</div>
);
}
}
class MouseTracker extends React.Component {
render() {
return (
<>
<h2>Move the mouse around!</h2>
<Mouse />
</>
);
}
}
Now the <Mouse>
component encapsulates all behavior associated with listening for mousemove
events and storing the (x, y) position of the cursor, but it's not yet truly reusable.
For example, let's say we have a <Cat>
component that renders the image of a cat chasing the mouse around the screen.
We might use a <Cat mouse={{ x, y }}>
prop to tell the component the coordinates of the mouse so it knows where to position the image on the screen.
As a first pass, you might try rendering the <Cat>
inside <Mouse>
's render
method, like this:
class Cat extends React.Component {
render() {
const mouse = this.props.mouse;
return (
<img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />
);
}
}
class MouseWithCat extends React.Component {
constructor(props) {
super(props);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.state = { x: 0, y: 0 };
}
handleMouseMove(event) {
this.setState({
x: event.clientX,
y: event.clientY
});
}
render() {
return (
<div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}>
{/*
We could just swap out the <p> for a <Cat> here ...
but then
we would need to create a separate <MouseWithSomethingElse>
component every time we need to use it, so <MouseWithCat>
isn't really reusable yet.
*/}
<Cat mouse={this.state} />
</div>
);
}
}
class MouseTracker extends React.Component {
render() {
return (
<div>
<h2>Move the mouse around!</h2>
<MouseWithCat />
</div>
);
}
}
This approach will work for our specific use case, but we haven't achieved the objective of truly encapsulating the behavior in a reusable way.
Now, every time we want the mouse position for a different use case, we have to create a new component (i.e.
essentially another <MouseWithCat>
) that renders something specifically for that use case.
Here's where the render prop comes in: Instead of hard-coding a <Cat>
inside a <Mouse>
component, and effectively changing its rendered output, we can provide <Mouse>
with a function prop that it uses to dynamically determine what to render¨Ca render prop.
class Cat extends React.Component {
render() {
const mouse = this.props.mouse;
return (
<img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />
);
}
}
class Mouse extends React.Component {
constructor(props) {
super(props);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.state = { x: 0, y: 0 };
}
handleMouseMove(event) {
this.setState({
x: event.clientX,
y: event.clientY
});
}
render() {
return (
<div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}>
{/*
Instead of providing a static representation of what <Mouse> renders,
use the `render` prop to dynamically determine what to render.
*/}
{this.props.render(this.state)}
</div>
);
}
}
class MouseTracker extends React.Component {
render() {
return (
<div>
<h2>Move the mouse around!</h2>
<Mouse render={mouse => (
<Cat mouse={mouse} />
)}/>
</div>
);
}
}
Now, instead of effectively cloning the <Mouse>
component and hard-coding something else in its render
method to solve for a specific use case, we provide a render
prop that <Mouse>
can use to dynamically determine what it renders.
More concretely, a render prop is a function prop that a component uses to know what to render.
This technique makes the behavior that we need to share extremely portable.
To get that behavior, render a <Mouse>
with a render
prop that tells it what to render with the current (x, y) of the cursor.
One interesting thing to note about render props is that you can implement most higher-order components (HOC) using a regular component with a render prop.
For example, if you would prefer to have a withMouse
HOC instead of a <Mouse>
component, you could easily create one using a regular <Mouse>
with a render prop:
// If you really want a HOC for some reason, you can easily
// create one using a regular component with a render prop!
function withMouse(Component) {
return class extends React.Component {
render() {
return (
<Mouse render={mouse => (
<Component {...this.props} mouse={mouse} />
)}/>
);
}
}
}
So using a render prop makes it possible to use either pattern.
Using Props Other Than render
It's important to remember that just because the pattern is called ¡°render props¡± you don't have to use a prop named render
to use this pattern.
In fact, any prop that is a function that a component uses to know what to render is technically a ¡°render prop¡±.
Although the examples above use render
, we could just as easily use the children
prop!
<Mouse children={mouse => (
<p>The mouse position is {mouse.x}, {mouse.y}</p>
)}/>
And remember, the children
prop doesn't actually need to be named in the list of ¡°attributes¡± in your JSX element.
Instead, you can put it directly inside the element!
<Mouse>
{mouse => (
<p>The mouse position is {mouse.x}, {mouse.y}</p>
)}
</Mouse>
You'll see this technique used in the react-motion API.
Since this technique is a little unusual, you'll probably want to explicitly state that children
should be a function in your propTypes
when designing an API like this.
Mouse.propTypes = {
children: PropTypes.func.isRequired
};
Caveats
Be careful when using Render Props with React.PureComponent
Using a render prop can negate the advantage that comes from using React.PureComponent
if you create the function inside a render
method.
This is because the shallow prop comparison will always return false
for new props, and each render
in this case will generate a new value for the render prop.
For example, continuing with our <Mouse>
component from above, if Mouse
were to extend React.PureComponent
instead of React.Component
, our example would look like this:
class Mouse extends React.PureComponent {
// Same implementation as above...
}
class MouseTracker extends React.Component {
render() {
return (
<div>
<h2>Move the mouse around!</h2>
{/*
This is bad! The value of the `render` prop will
be different on each render.
*/}
<Mouse render={mouse => (
<Cat mouse={mouse} />
)}/>
</div>
);
}
}
In this example, each time <MouseTracker>
renders, it generates a new function as the value of the <Mouse render>
prop, thus negating the effect of <Mouse>
extending React.PureComponent
in the first place!
To get around this problem, you can sometimes define the prop as an instance method, like so:
class MouseTracker extends React.Component {
// Defined as an instance method, `this.renderTheCat` always
// refers to *same* function when we use it in render
renderTheCat(mouse) {
return <Cat mouse={mouse} />;
}
render() {
return (
<div>
<h2>Move the mouse around!</h2>
<Mouse render={this.renderTheCat} />
</div>
);
}
}
In cases where you cannot define the prop statically (e.g.
because you need to close over the component's props and/or state) <Mouse>
should extend React.Component
instead.
Static Type Checking
Static type checkers like Flow and TypeScript identify certain types of problems before you even run your code.
They can also improve developer workflow by adding features like auto-completion.
For this reason, we recommend using Flow or TypeScript instead of PropTypes
for larger code bases.
Flow
Flow is a static type checker for your JavaScript code.
It is developed at Facebook and is often used with React.
It lets you annotate the variables, functions, and React components with a special type syntax, and catch mistakes early.
You can read an introduction to Flow to learn its basics.
To use Flow, you need to:
- Add Flow to your project as a dependency.
- Ensure that Flow syntax is stripped from the compiled code.
- Add type annotations and run Flow to check them.
We will explain these steps below in detail.
Adding Flow to a Project
First, navigate to your project directory in the terminal.
You will need to run the following command:
If you use Yarn, run:
yarn add --dev flow-bin
If you use npm, run:
npm install --save-dev flow-bin
This command installs the latest version of Flow into your project.
Now, add flow
to the "scripts"
section of your package.json
to be able to use this from the terminal:
{
// ...
"scripts": {
"flow": "flow", // ...
},
// ...
}
Finally, run one of the following commands:
If you use Yarn, run:
yarn run flow init
If you use npm, run:
npm run flow init
This command will create a Flow configuration file that you will need to commit.
Stripping Flow Syntax from the Compiled Code
Flow extends the JavaScript language with a special syntax for type annotations.
However, browsers aren't aware of this syntax, so we need to make sure it doesn't end up in the compiled JavaScript bundle that is sent to the browser.
The exact way to do this depends on the tools you use to compile JavaScript.
Create React App
If your project was set up using Create React App, congratulations! The Flow annotations are already being stripped by default so you don't need to do anything else in this step.
Babel
Note:
These instructions are not for Create React App users.
Even though Create React App uses Babel under the hood, it is already configured to understand Flow.
Only follow this step if you don't use Create React App.
If you manually configured Babel for your project, you will need to install a special preset for Flow.
If you use Yarn, run:
yarn add --dev @babel/preset-flow
If you use npm, run:
npm install --save-dev @babel/preset-flow
Then add the flow
preset to your Babel configuration.
For example, if you configure Babel through .babelrc
file, it could look like this:
{
"presets": [
"@babel/preset-flow", "react"
]
}
This will let you use the Flow syntax in your code.
Note:
Flow does not require the react
preset, but they are often used together.
Flow itself understands JSX syntax out of the box.
Other Build Setups
If you don't use either Create React App or Babel, you can use flow-remove-types to strip the type annotations.
Running Flow
If you followed the instructions above, you should be able to run Flow for the first time.
yarn flow
If you use npm, run:
npm run flow
You should see a message like:
No errors!
Done in 0.17s.
Adding Flow Type Annotations
By default, Flow only checks the files that include this annotation:
// @flow
Typically it is placed at the top of a file.
Try adding it to some files in your project and run yarn flow
or npm run flow
to see if Flow already found any issues.
There is also an option to force Flow to check all files regardless of the annotation.
This can be too noisy for existing projects, but is reasonable for a new project if you want to fully type it with Flow.
Now you're all set! We recommend to check out the following resources to learn more about Flow:
- Flow Documentation: Type Annotations
- Flow Documentation: Editors
- Flow Documentation: React
- Linting in Flow
TypeScript
TypeScript is a programming language developed by Microsoft.
It is a typed superset of JavaScript, and includes its own compiler.
Being a typed language, TypeScript can catch errors and bugs at build time, long before your app goes live.
You can learn more about using TypeScript with React here.
To use TypeScript, you need to:
- Add TypeScript as a dependency to your project
- Configure the TypeScript compiler options
- Use the right file extensions
- Add definitions for libraries you use
Let's go over these in detail.
Using TypeScript with Create React App
Create React App supports TypeScript out of the box.
To create a new project with TypeScript support, run:
npx create-react-app my-app --template typescript
You can also add it to an existing Create React App project, as documented here.
Note:
If you use Create React App, you can skip the rest of this page.
It describes the manual setup which doesn't apply to Create React App users.
Adding TypeScript to a Project
It all begins with running one command in your terminal.
If you use Yarn, run:
yarn add --dev typescript
If you use npm, run:
npm install --save-dev typescript
Congrats! You've installed the latest version of TypeScript into your project.
Installing TypeScript gives us access to the tsc
command.
Before configuration, let's add tsc
to the ¡°scripts¡± section in our package.json
:
{
// ...
"scripts": {
"build": "tsc", // ...
},
// ...
}
Configuring the TypeScript Compiler
The compiler is of no help to us until we tell it what to do.
In TypeScript, these rules are defined in a special file called tsconfig.json
.
To generate this file:
If you use Yarn, run:
yarn run tsc --init
If you use npm, run:
npx tsc --init
Looking at the now generated tsconfig.json
, you can see that there are many options you can use to configure the compiler.
For a detailed description of all the options, check here.
Of the many options, we'll look at rootDir
and outDir
.
In its true fashion, the compiler will take in typescript files and generate javascript files.
However we don't want to get confused with our source files and the generated output.
We'll address this in two steps:
- Firstly, let's arrange our project structure like this.
We'll place all our source code in the
src
directory.
©À©¤©¤ package.json
©À©¤©¤ src
©¦ ©¸©¤©¤ index.ts
©¸©¤©¤ tsconfig.json
- Next, we'll tell the compiler where our source code is and where the output should go.
// tsconfig.json
{
"compilerOptions": {
// ...
"rootDir": "src", "outDir": "build" // ...
},
}
Great! Now when we run our build script the compiler will output the generated javascript to the build
folder.
The TypeScript React Starter provides a tsconfig.json
with a good set of rules to get you started.
Generally, you don't want to keep the generated javascript in your source control, so be sure to add the build folder to your .gitignore
.
File extensions
In React, you most likely write your components in a .js
file.
In TypeScript we have 2 file extensions:
.ts
is the default file extension while .tsx
is a special extension used for files which contain JSX
.
Running TypeScript
If you followed the instructions above, you should be able to run TypeScript for the first time.
yarn build
If you use npm, run:
npm run build
If you see no output, it means that it completed successfully.
Type Definitions
To be able to show errors and hints from other packages, the compiler relies on declaration files.
A declaration file provides all the type information about a library.
This enables us to use javascript libraries like those on npm in our project.
There are two main ways to get declarations for a library:
Bundled - The library bundles its own declaration file.
This is great for us, since all we need to do is install the library, and we can use it right away.
To check if a library has bundled types, look for an index.d.ts
file in the project.
Some libraries will have it specified in their package.json
under the typings
or types
field.
DefinitelyTyped - DefinitelyTyped is a huge repository of declarations for libraries that don't bundle a declaration file.
The declarations are crowd-sourced and managed by Microsoft and open source contributors.
React for example doesn't bundle its own declaration file.
Instead we can get it from DefinitelyTyped.
To do so enter this command in your terminal.
# yarn
yarn add --dev @types/react
# npm
npm i --save-dev @types/react
Local Declarations
Sometimes the package that you want to use doesn't bundle declarations nor is it available on DefinitelyTyped.
In that case, we can have a local declaration file.
To do this, create a declarations.d.ts
file in the root of your source directory.
A simple declaration could look like this:
declare module 'querystring' {
export function stringify(val: object): string
export function parse(val: string): object
}
You are now ready to code! We recommend to check out the following resources to learn more about TypeScript:
- TypeScript Documentation: Basic Types
- TypeScript Documentation: Migrating from Javascript
- TypeScript Documentation: React and Webpack
Reason
Reason is not a new language; it's a new syntax and toolchain powered by the battle-tested language, OCaml.
Reason gives OCaml a familiar syntax geared toward JavaScript programmers, and caters to the existing NPM/Yarn workflow folks already know.
Reason is developed at Facebook, and is used in some of its products like Messenger.
It is still somewhat experimental but it has dedicated React bindings maintained by Facebook and a vibrant community.
Kotlin
Kotlin is a statically typed language developed by JetBrains.
Its target platforms include the JVM, Android, LLVM, and JavaScript.
JetBrains develops and maintains several tools specifically for the React community: React bindings as well as Create React Kotlin App.
The latter helps you start building React apps with Kotlin with no build configuration.
Other Languages
Note there are other statically typed languages that compile to JavaScript and are thus React compatible.
For example, F#/Fable with elmish-react.
Check out their respective sites for more information, and feel free to add more statically typed languages that work with React to this page!
Strict Mode
StrictMode
is a tool for highlighting potential problems in an application.
Like Fragment
, StrictMode
does not render any visible UI.
It activates additional checks and warnings for its descendants.
Note:
Strict mode checks are run in development mode only; they do not impact the production build.
You can enable strict mode for any part of your application.
For example:
import React from 'react';
function ExampleApplication() {
return (
<div>
<Header />
<React.StrictMode> <div>
<ComponentOne />
<ComponentTwo />
</div>
</React.StrictMode> <Footer />
</div>
);
}
In the above example, strict mode checks will not be run against the Header
and Footer
components.
However, ComponentOne
and ComponentTwo
, as well as all of their descendants, will have the checks.
StrictMode
currently helps with:
- Identifying components with unsafe lifecycles
- Warning about legacy string ref API usage
- Warning about deprecated findDOMNode usage
- Detecting unexpected side effects
- Detecting legacy context API
Additional functionality will be added with future releases of React.
Identifying unsafe lifecycles
As explained in this blog post, certain legacy lifecycle methods are unsafe for use in async React applications.
However, if your application uses third party libraries, it can be difficult to ensure that these lifecycles aren't being used.
Fortunately, strict mode can help with this!
When strict mode is enabled, React compiles a list of all class components using the unsafe lifecycles, and logs a warning message with information about these components, like so:
Addressing the issues identified by strict mode now will make it easier for you to take advantage of concurrent rendering in future releases of React.
Warning about legacy string ref API usage
Previously, React provided two ways for managing refs: the legacy string ref API and the callback API.
Although the string ref API was the more convenient of the two, it had several downsides and so our official recommendation was to use the callback form instead.
React 16.3 added a third option that offers the convenience of a string ref without any of the downsides:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef(); }
render() {
return <input type="text" ref={this.inputRef} />; }
componentDidMount() {
this.inputRef.current.focus(); }
}
Since object refs were largely added as a replacement for string refs, strict mode now warns about usage of string refs.
Note:
Callback refs will continue to be supported in addition to the new createRef
API.
You don't need to replace callback refs in your components.
They are slightly more flexible, so they will remain as an advanced feature.
Learn more about the new createRef
API here.
Warning about deprecated findDOMNode usage
React used to support findDOMNode
to search the tree for a DOM node given a class instance.
Normally you don't need this because you can attach a ref directly to a DOM node.
findDOMNode
can also be used on class components but this was breaking abstraction levels by allowing a parent to demand that certain children was rendered.
It creates a refactoring hazard where you can't change the implementation details of a component because a parent might be reaching into its DOM node.
findDOMNode
only returns the first child, but with the use of Fragments, it is possible for a component to render multiple DOM nodes.
findDOMNode
is a one time read API.
It only gave you an answer when you asked for it.
If a child component renders a different node, there is no way to handle this change.
Therefore findDOMNode
only worked if components always return a single DOM node that never changes.
You can instead make this explicit by passing a ref to your custom component and pass that along to the DOM using ref forwarding.
You can also add a wrapper DOM node in your component and attach a ref directly to it.
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.wrapper = React.createRef(); }
render() {
return <div ref={this.wrapper}>{this.props.children}</div>; }
}
Note:
In CSS, the display: contents
attribute can be used if you don't want the node to be part of the layout.
Detecting unexpected side effects
Conceptually, React does work in two phases:
- The render phase determines what changes need to be made to e.g.
the DOM.
During this phase, React calls
render
and then compares the result to the previous render.
- The commit phase is when React applies any changes.
(In the case of React DOM, this is when React inserts, updates, and removes DOM nodes.) React also calls lifecycles like
componentDidMount
and componentDidUpdate
during this phase.
The commit phase is usually very fast, but rendering can be slow.
For this reason, the upcoming concurrent mode (which is not enabled by default yet) breaks the rendering work into pieces, pausing and resuming the work to avoid blocking the browser.
This means that React may invoke render phase lifecycles more than once before committing, or it may invoke them without committing at all (because of an error or a higher priority interruption).
Render phase lifecycles include the following class component methods:
constructor
-
componentWillMount
(or UNSAFE_componentWillMount
)
-
componentWillReceiveProps
(or UNSAFE_componentWillReceiveProps
)
-
componentWillUpdate
(or UNSAFE_componentWillUpdate
)
getDerivedStateFromProps
shouldComponentUpdate
render
-
setState
updater functions (the first argument)
Because the above methods might be called more than once, it's important that they do not contain side-effects.
Ignoring this rule can lead to a variety of problems, including memory leaks and invalid application state.
Unfortunately, it can be difficult to detect these problems as they can often be non-deterministic.
Strict mode can't automatically detect side effects for you, but it can help you spot them by making them a little more deterministic.
This is done by intentionally double-invoking the following functions:
- Class component
constructor
, render
, and shouldComponentUpdate
methods
- Class component static
getDerivedStateFromProps
method
- Function component bodies
- State updater functions (the first argument to
setState
)
- Functions passed to
useState
, useMemo
, or useReducer
Note:
This only applies to development mode.
Lifecycles will not be double-invoked in production mode.
For example, consider the following code:
class TopLevelRoute extends React.Component {
constructor(props) {
super(props);
SharedApplicationState.recordEvent('ExampleComponent');
}
}
At first glance, this code might not seem problematic.
But if SharedApplicationState.recordEvent
is not idempotent, then instantiating this component multiple times could lead to invalid application state.
This sort of subtle bug might not manifest during development, or it might do so inconsistently and so be overlooked.
By intentionally double-invoking methods like the component constructor, strict mode makes patterns like this easier to spot.
Note:
Starting with React 17, React automatically modifies the console methods like console.log()
to silence the logs in the second call to lifecycle functions.
However, it may cause undesired behavior in certain cases where a workaround can be used.
Detecting legacy context API
The legacy context API is error-prone, and will be removed in a future major version.
It still works for all 16.x releases but will show this warning message in strict mode:
Read the new context API documentation to help migrate to the new version.
Typechecking With PropTypes
Note:
React.PropTypes
has moved into a different package since React v15.5.
Please use the prop-types
library instead.
We provide a codemod script to automate the conversion.
As your app grows, you can catch a lot of bugs with typechecking.
For some applications, you can use JavaScript extensions like Flow or TypeScript to typecheck your whole application.
But even if you don't use those, React has some built-in typechecking abilities.
To run typechecking on the props for a component, you can assign the special propTypes
property:
import PropTypes from 'prop-types';
class Greeting extends React.Component {
render() {
return (
<h2>Hello, {this.props.name}</h2>
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};
In this example, we are using a class component, but the same functionality could also be applied to function components, or components created by React.memo
or React.forwardRef
.
PropTypes
exports a range of validators that can be used to make sure the data you receive is valid.
In this example, we're using PropTypes.string
.
When an invalid value is provided for a prop, a warning will be shown in the JavaScript console.
For performance reasons, propTypes
is only checked in development mode.
PropTypes
Here is an example documenting the different validators provided:
import PropTypes from 'prop-types';
MyComponent.propTypes = {
// You can declare that a prop is a specific JS type.
By default, these
// are all optional.
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,
// Anything that can be rendered: numbers, strings, elements or an array
// (or fragment) containing these types.
optionalNode: PropTypes.node,
// A React element.
optionalElement: PropTypes.element,
// A React element type (ie.
MyComponent).
optionalElementType: PropTypes.elementType,
// You can also declare that a prop is an instance of a class.
This uses
// JS's instanceof operator.
optionalMessage: PropTypes.instanceOf(Message),
// You can ensure that your prop is limited to specific values by treating
// it as an enum.
optionalEnum: PropTypes.oneOf(['News', 'Photos']),
// An object that could be one of many types
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Message)
]),
// An array of a certain type
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
// An object with property values of a certain type
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
// An object taking on a particular shape
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),
// An object with warnings on extra properties
optionalObjectWithStrictShape: PropTypes.exact({
name: PropTypes.string,
quantity: PropTypes.number
}),
// You can chain any of the above with `isRequired` to make sure a warning
// is shown if the prop isn't provided.
requiredFunc: PropTypes.func.isRequired,
// A required value of any data type
requiredAny: PropTypes.any.isRequired,
// You can also specify a custom validator.
It should return an Error
// object if the validation fails.
Don't `console.warn` or throw, as this
// won't work inside `oneOfType`.
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`.
Validation failed.'
);
}
},
// You can also supply a custom validator to `arrayOf` and `objectOf`.
// It should return an Error object if the validation fails.
The validator
// will be called for each key in the array or object.
The first two
// arguments of the validator are the array or object itself, and the
// current item's key.
customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
if (!/matchme/.test(propValue[key])) {
return new Error(
'Invalid prop `' + propFullName + '` supplied to' +
' `' + componentName + '`.
Validation failed.'
);
}
})
};
Requiring Single Child
With PropTypes.element
you can specify that only a single child can be passed to a component as children.
import PropTypes from 'prop-types';
class MyComponent extends React.Component {
render() {
// This must be exactly one element or it will warn.
const children = this.props.children;
return (
<div>
{children}
</div>
);
}
}
MyComponent.propTypes = {
children: PropTypes.element.isRequired
};
Default Prop Values
You can define default values for your props
by assigning to the special defaultProps
property:
class Greeting extends React.Component {
render() {
return (
<h2>Hello, {this.props.name}</h2>
);
}
}
// Specifies the default values for props:
Greeting.defaultProps = {
name: 'Stranger'
};
// Renders "Hello, Stranger":
ReactDOM.render(
<Greeting />,
document.getElementById('example')
);
If you are using a Babel transform like transform-class-properties , you can also declare defaultProps
as static property within a React component class.
This syntax has not yet been finalized though and will require a compilation step to work within a browser.
For more information, see the class fields proposal.
class Greeting extends React.Component {
static defaultProps = {
name: 'stranger'
}
render() {
return (
<div>Hello, {this.props.name}</div>
)
}
}
The defaultProps
will be used to ensure that this.props.name
will have a value if it was not specified by the parent component.
The propTypes
typechecking happens after defaultProps
are resolved, so typechecking will also apply to the defaultProps
.
Function Components
If you are using function components in your regular development, you may want to make some small changes to allow PropTypes to be properly applied.
Let's say you have a component like this:
export default function HelloWorldComponent({ name }) {
return (
<div>Hello, {name}</div>
)
}
To add PropTypes, you may want to declare the component in a separate function before exporting, like this:
function HelloWorldComponent({ name }) {
return (
<div>Hello, {name}</div>
)
}
export default HelloWorldComponent
Then, you can add PropTypes directly to the HelloWorldComponent
:
import PropTypes from 'prop-types'
function HelloWorldComponent({ name }) {
return (
<div>Hello, {name}</div>
)
}
HelloWorldComponent.propTypes = {
name: PropTypes.string
}
export default HelloWorldComponent
Uncontrolled Components
In most cases, we recommend using controlled components to implement forms.
In a controlled component, form data is handled by a React component.
The alternative is uncontrolled components, where form data is handled by the DOM itself.
To write an uncontrolled component, instead of writing an event handler for every state update, you can use a ref to get form values from the DOM.
For example, this code accepts a single name in an uncontrolled component:
class NameForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.input = React.createRef(); }
handleSubmit(event) {
alert('A name was submitted: ' + this.input.current.value); event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" ref={this.input} /> </label>
<input type="submit" value="Submit" />
</form>
);
}
}
Try it on CodePen
Since an uncontrolled component keeps the source of truth in the DOM, it is sometimes easier to integrate React and non-React code when using uncontrolled components.
It can also be slightly less code if you want to be quick and dirty.
Otherwise, you should usually use controlled components.
If it's still not clear which type of component you should use for a particular situation, you might find this article on controlled versus uncontrolled inputs to be helpful.
Default Values
In the React rendering lifecycle, the value
attribute on form elements will override the value in the DOM.
With an uncontrolled component, you often want React to specify the initial value, but leave subsequent updates uncontrolled.
To handle this case, you can specify a defaultValue
attribute instead of value
.
Changing the value of defaultValue
attribute after a component has mounted will not cause any update of the value in the DOM.
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input
defaultValue="Bob" type="text"
ref={this.input} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
Likewise, <input type="checkbox">
and <input type="radio">
support defaultChecked
, and <select>
and <textarea>
supports defaultValue
.
The file input Tag
In HTML, an <input type="file">
lets the user choose one or more files from their device storage to be uploaded to a server or manipulated by JavaScript via the File API.
<input type="file" />
In React, an <input type="file" />
is always an uncontrolled component because its value can only be set by a user, and not programmatically.
You should use the File API to interact with the files.
The following example shows how to create a ref to the DOM node to access file(s) in a submit handler:
class FileInput extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.fileInput = React.createRef(); }
handleSubmit(event) {
event.preventDefault();
alert(
`Selected file - ${this.fileInput.current.files[0].name}` );
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Upload file:
<input type="file" ref={this.fileInput} /> </label>
<br />
<button type="submit">Submit</button>
</form>
);
}
}
ReactDOM.render(
<FileInput />,
document.getElementById('root')
);
Try it on CodePen
Web Components
React and Web Components are built to solve different problems.
Web Components provide strong encapsulation for reusable components, while React provides a declarative library that keeps the DOM in sync with your data.
The two goals are complementary.
As a developer, you are free to use React in your Web Components, or to use Web Components in React, or both.
Most people who use React don't use Web Components, but you may want to, especially if you are using third-party UI components that are written using Web Components.
Using Web Components in React
class HelloMessage extends React.Component {
render() {
return <div>Hello <x-search>{this.props.name}</x-search>!</div>;
}
}
Note:
Web Components often expose an imperative API.
For instance, a video
Web Component might expose play()
and pause()
functions.
To access the imperative APIs of a Web Component, you will need to use a ref to interact with the DOM node directly.
If you are using third-party Web Components, the best solution is to write a React component that behaves as a wrapper for your Web Component.
Events emitted by a Web Component may not properly propagate through a React render tree.
You will need to manually attach event handlers to handle these events within your React components.
One common confusion is that Web Components use ¡°class¡± instead of ¡°className¡±.
function BrickFlipbox() {
return (
<brick-flipbox class="demo">
<div>front</div>
<div>back</div>
</brick-flipbox>
);
}
Using React in your Web Components
class XSearch extends HTMLElement {
connectedCallback() {
const mountPoint = document.createElement('span');
this.attachShadow({ mode: 'open' }).appendChild(mountPoint);
const name = this.getAttribute('name');
const url = 'https://www.google.com/search?q=' + encodeURIComponent(name);
ReactDOM.render(<a href={url}>{name}</a>, mountPoint);
}
}
customElements.define('x-search', XSearch);
Note:
This code will not work if you transform classes with Babel.
See this issue for the discussion.
Include the custom-elements-es5-adapter before you load your web components to fix this issue.
React Top-Level API
React
is the entry point to the React library.
If you load React from a <script>
tag, these top-level APIs are available on the React
global.
If you use ES6 with npm, you can write import React from 'react'
.
If you use ES5 with npm, you can write var React = require('react')
.
Overview
Components
React components let you split the UI into independent, reusable pieces, and think about each piece in isolation.
React components can be defined by subclassing React.Component
or React.PureComponent
.
React.Component
React.PureComponent
If you don't use ES6 classes, you may use the create-react-class
module instead.
See Using React without ES6 for more information.
React components can also be defined as functions which can be wrapped:
Creating React Elements
We recommend using JSX to describe what your UI should look like.
Each JSX element is just syntactic sugar for calling React.createElement()
.
You will not typically invoke the following methods directly if you are using JSX.
createElement()
createFactory()
See Using React without JSX for more information.
Transforming Elements
React
provides several APIs for manipulating elements:
cloneElement()
isValidElement()
React.Children
Fragments
React
also provides a component for rendering multiple elements without a wrapper.
Refs
React.createRef
React.forwardRef
Suspense
Suspense lets components ¡°wait¡± for something before rendering.
Today, Suspense only supports one use case: loading components dynamically with React.lazy
.
In the future, it will support other use cases like data fetching.
React.lazy
React.Suspense
Hooks
Hooks are a new addition in React 16.8.
They let you use state and other React features without writing a class.
Hooks have a dedicated docs section and a separate API reference:
-
Basic Hooks
useState
useEffect
useContext
-
Additional Hooks
useReducer
useCallback
useMemo
useRef
useImperativeHandle
useLayoutEffect
useDebugValue
Reference
React.Component
React.Component
is the base class for React components when they are defined using ES6 classes:
class Greeting extends React.Component {
render() {
return <h2>Hello, {this.props.name}</h2>;
}
}
See the React.Component API Reference for a list of methods and properties related to the base React.Component
class.
React.PureComponent
React.PureComponent
is similar to React.Component
.
The difference between them is that React.Component
doesn't implement shouldComponentUpdate()
, but React.PureComponent
implements it with a shallow prop and state comparison.
If your React component's render()
function renders the same result given the same props and state, you can use React.PureComponent
for a performance boost in some cases.
Note
React.PureComponent
's shouldComponentUpdate()
only shallowly compares the objects.
If these contain complex data structures, it may produce false-negatives for deeper differences.
Only extend PureComponent
when you expect to have simple props and state, or use forceUpdate()
when you know deep data structures have changed.
Or, consider using immutable objects to facilitate fast comparisons of nested data.
Furthermore, React.PureComponent
's shouldComponentUpdate()
skips prop updates for the whole component subtree.
Make sure all the children components are also ¡°pure¡±.
React.memo
const MyComponent = React.memo(function MyComponent(props) {
/* render using props */
});
React.memo
is a higher order component.
If your component renders the same result given the same props, you can wrap it in a call to React.memo
for a performance boost in some cases by memoizing the result.
This means that React will skip rendering the component, and reuse the last rendered result.
React.memo
only checks for prop changes.
If your function component wrapped in React.memo
has a useState
or useContext
Hook in its implementation, it will still rerender when state or context change.
By default it will only shallowly compare complex objects in the props object.
If you want control over the comparison, you can also provide a custom comparison function as the second argument.
function MyComponent(props) {
/* render using props */
}
function areEqual(prevProps, nextProps) {
/*
return true if passing nextProps to render would return
the same result as passing prevProps to render,
otherwise return false
*/
}
export default React.memo(MyComponent, areEqual);
This method only exists as a performance optimization. Do not rely on it to ¡°prevent¡± a render, as this can lead to bugs.
Note
Unlike the shouldComponentUpdate()
method on class components, the areEqual
function returns true
if the props are equal and false
if the props are not equal.
This is the inverse from shouldComponentUpdate
.
createElement()
React.createElement(
type,
[props],
[...children]
)
Create and return a new React element of the given type.
The type argument can be either a tag name string (such as 'div'
or 'span'
), a React component type (a class or a function), or a React fragment type.
Code written with JSX will be converted to use React.createElement()
.
You will not typically invoke React.createElement()
directly if you are using JSX.
See React Without JSX to learn more.
cloneElement()
React.cloneElement(
element,
[props],
[...children]
)
Clone and return a new React element using element
as the starting point.
The resulting element will have the original element's props with the new props merged in shallowly.
New children will replace existing children.
key
and ref
from the original element will be preserved.
React.cloneElement()
is almost equivalent to:
<element.type {...element.props} {...props}>{children}</element.type>
However, it also preserves ref
s.
This means that if you get a child with a ref
on it, you won't accidentally steal it from your ancestor.
You will get the same ref
attached to your new element.
This API was introduced as a replacement of the deprecated React.addons.cloneWithProps()
.
createFactory()
React.createFactory(type)
Return a function that produces React elements of a given type.
Like React.createElement()
, the type argument can be either a tag name string (such as 'div'
or 'span'
), a React component type (a class or a function), or a React fragment type.
This helper is considered legacy, and we encourage you to either use JSX or use React.createElement()
directly instead.
You will not typically invoke React.createFactory()
directly if you are using JSX.
See React Without JSX to learn more.
isValidElement()
React.isValidElement(object)
Verifies the object is a React element.
Returns true
or false
.
React.Children
React.Children
provides utilities for dealing with the this.props.children
opaque data structure.
React.Children.map
React.Children.map(children, function[(thisArg)])
Invokes a function on every immediate child contained within children
with this
set to thisArg
.
If children
is an array it will be traversed and the function will be called for each child in the array.
If children is null
or undefined
, this method will return null
or undefined
rather than an array.
Note
If children
is a Fragment
it will be treated as a single child and not traversed.
React.Children.forEach
React.Children.forEach(children, function[(thisArg)])
Like React.Children.map()
but does not return an array.
React.Children.count
React.Children.count(children)
Returns the total number of components in children
, equal to the number of times that a callback passed to map
or forEach
would be invoked.
React.Children.only
React.Children.only(children)
Verifies that children
has only one child (a React element) and returns it.
Otherwise this method throws an error.
Note:
React.Children.only()
does not accept the return value of React.Children.map()
because it is an array rather than a React element.
React.Children.toArray
React.Children.toArray(children)
Returns the children
opaque data structure as a flat array with keys assigned to each child.
Useful if you want to manipulate collections of children in your render methods, especially if you want to reorder or slice this.props.children
before passing it down.
Note:
React.Children.toArray()
changes keys to preserve the semantics of nested arrays when flattening lists of children.
That is, toArray
prefixes each key in the returned array so that each element's key is scoped to the input array containing it.
React.Fragment
The React.Fragment
component lets you return multiple elements in a render()
method without creating an additional DOM element:
render() {
return (
<React.Fragment>
Some text.
<h3>A heading</h3>
</React.Fragment>
);
}
You can also use it with the shorthand <></>
syntax.
For more information, see React v16.2.0: Improved Support for Fragments.
React.createRef
React.createRef
creates a ref that can be attached to React elements via the ref attribute.
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef(); }
render() {
return <input type="text" ref={this.inputRef} />; }
componentDidMount() {
this.inputRef.current.focus(); }
}
React.forwardRef
React.forwardRef
creates a React component that forwards the ref attribute it receives to another component below in the tree.
This technique is not very common but is particularly useful in two scenarios:
- Forwarding refs to DOM components
- Forwarding refs in higher-order-components
React.forwardRef
accepts a rendering function as an argument.
React will call this function with props
and ref
as two arguments.
This function should return a React node.
const FancyButton = React.forwardRef((props, ref) => ( <button ref={ref} className="FancyButton"> {props.children}
</button>
));
// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
In the above example, React passes a ref
given to <FancyButton ref={ref}>
element as a second argument to the rendering function inside the React.forwardRef
call.
This rendering function passes the ref
to the <button ref={ref}>
element.
As a result, after React attaches the ref, ref.current
will point directly to the <button>
DOM element instance.
For more information, see forwarding refs.
React.lazy
React.lazy()
lets you define a component that is loaded dynamically.
This helps reduce the bundle size to delay loading components that aren't used during the initial render.
You can learn how to use it from our code splitting documentation.
You might also want to check out this article explaining how to use it in more detail.
// This component is loaded dynamically
const SomeComponent = React.lazy(() => import('./SomeComponent'));
Note that rendering lazy
components requires that there's a <React.Suspense>
component higher in the rendering tree.
This is how you specify a loading indicator.
Note
Using React.lazy
with dynamic import requires Promises to be available in the JS environment.
This requires a polyfill on IE11 and below.
React.Suspense
React.Suspense
lets you specify the loading indicator in case some components in the tree below it are not yet ready to render.
Today, lazy loading components is the only use case supported by <React.Suspense>
:
// This component is loaded dynamically
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
// Displays <Spinner> until OtherComponent loads
<React.Suspense fallback={<Spinner />}>
<div>
<OtherComponent />
</div>
</React.Suspense>
);
}
It is documented in our code splitting guide.
Note that lazy
components can be deep inside the Suspense
tree ¡ª it doesn't have to wrap every one of them.
The best practice is to place <Suspense>
where you want to see a loading indicator, but to use lazy()
wherever you want to do code splitting.
While this is not supported today, in the future we plan to let Suspense
handle more scenarios such as data fetching.
You can read about this in our roadmap.
Note:
React.lazy()
and <React.Suspense>
are not yet supported by ReactDOMServer
.
This is a known limitation that will be resolved in the future.
ReactDOM
If you load React from a <script>
tag, these top-level APIs are available on the ReactDOM
global.
If you use ES6 with npm, you can write import ReactDOM from 'react-dom'
.
If you use ES5 with npm, you can write var ReactDOM = require('react-dom')
.
Overview
The react-dom
package provides DOM-specific methods that can be used at the top level of your app and as an escape hatch to get outside of the React model if you need to.
Most of your components should not need to use this module.
render()
hydrate()
unmountComponentAtNode()
findDOMNode()
createPortal()
Browser Support
React supports all popular browsers, including Internet Explorer 9 and above, although some polyfills are required for older browsers such as IE 9 and IE 10.
Note
We don't support older browsers that don't support ES5 methods, but you may find that your apps do work in older browsers if polyfills such as es5-shim and es5-sham are included in the page.
You're on your own if you choose to take this path.
Reference
render()
ReactDOM.render(element, container[, callback])
Render a React element into the DOM in the supplied container
and return a reference to the component (or returns null
for stateless components).
If the React element was previously rendered into container
, this will perform an update on it and only mutate the DOM as necessary to reflect the latest React element.
If the optional callback is provided, it will be executed after the component is rendered or updated.
Note:
ReactDOM.render()
controls the contents of the container node you pass in.
Any existing DOM elements inside are replaced when first called.
Later calls use React's DOM diffing algorithm for efficient updates.
ReactDOM.render()
does not modify the container node (only modifies the children of the container).
It may be possible to insert a component to an existing DOM node without overwriting the existing children.
ReactDOM.render()
currently returns a reference to the root ReactComponent
instance.
However, using this return value is legacy
and should be avoided because future versions of React may render components asynchronously in some cases.
If you need a reference to the root ReactComponent
instance, the preferred solution is to attach a
callback ref to the root element.
Using ReactDOM.render()
to hydrate a server-rendered container is deprecated and will be removed in React 17.
Use hydrate()
instead.
hydrate()
ReactDOM.hydrate(element, container[, callback])
Same as render()
, but is used to hydrate a container whose HTML contents were rendered by ReactDOMServer
.
React will attempt to attach event listeners to the existing markup.
React expects that the rendered content is identical between the server and the client.
It can patch up differences in text content, but you should treat mismatches as bugs and fix them.
In development mode, React warns about mismatches during hydration.
There are no guarantees that attribute differences will be patched up in case of mismatches.
This is important for performance reasons because in most apps, mismatches are rare, and so validating all markup would be prohibitively expensive.
If a single element's attribute or text content is unavoidably different between the server and the client (for example, a timestamp), you may silence the warning by adding suppressHydrationWarning={true}
to the element.
It only works one level deep, and is intended to be an escape hatch.
Don't overuse it.
Unless it's text content, React still won't attempt to patch it up, so it may remain inconsistent until future updates.
If you intentionally need to render something different on the server and the client, you can do a two-pass rendering.
Components that render something different on the client can read a state variable like this.state.isClient
, which you can set to true
in componentDidMount()
.
This way the initial render pass will render the same content as the server, avoiding mismatches, but an additional pass will happen synchronously right after hydration.
Note that this approach will make your components slower because they have to render twice, so use it with caution.
Remember to be mindful of user experience on slow connections.
The JavaScript code may load significantly later than the initial HTML render, so if you render something different in the client-only pass, the transition can be jarring.
However, if executed well, it may be beneficial to render a ¡°shell¡± of the application on the server, and only show some of the extra widgets on the client.
To learn how to do this without getting the markup mismatch issues, refer to the explanation in the previous paragraph.
unmountComponentAtNode()
ReactDOM.unmountComponentAtNode(container)
Remove a mounted React component from the DOM and clean up its event handlers and state.
If no component was mounted in the container, calling this function does nothing.
Returns true
if a component was unmounted and false
if there was no component to unmount.
findDOMNode()
Note:
findDOMNode
is an escape hatch used to access the underlying DOM node.
In most cases, use of this escape hatch is discouraged because it pierces the component abstraction.
It has been deprecated in StrictMode
.
ReactDOM.findDOMNode(component)
If this component has been mounted into the DOM, this returns the corresponding native browser DOM element.
This method is useful for reading values out of the DOM, such as form field values and performing DOM measurements.
In most cases, you can attach a ref to the DOM node and avoid using findDOMNode
at all.
When a component renders to null
or false
, findDOMNode
returns null
.
When a component renders to a string, findDOMNode
returns a text DOM node containing that value.
As of React 16, a component may return a fragment with multiple children, in which case findDOMNode
will return the DOM node corresponding to the first non-empty child.
Note:
findDOMNode
only works on mounted components (that is, components that have been placed in the DOM).
If you try to call this on a component that has not been mounted yet (like calling findDOMNode()
in render()
on a component that has yet to be created) an exception will be thrown.
findDOMNode
cannot be used on function components.
createPortal()
ReactDOM.createPortal(child, container)
Creates a portal.
Portals provide a way to render children into a DOM node that exists outside the hierarchy of the DOM component.
ReactDOMServer
The ReactDOMServer
object enables you to render components to static markup.
Typically, it's used on a Node server:
// ES modules
import ReactDOMServer from 'react-dom/server';
// CommonJS
var ReactDOMServer = require('react-dom/server');
Overview
The following methods can be used in both the server and browser environments:
renderToString()
renderToStaticMarkup()
These additional methods depend on a package (stream
) that is only available on the server, and won't work in the browser.
renderToNodeStream()
renderToStaticNodeStream()
Reference
renderToString()
ReactDOMServer.renderToString(element)
Render a React element to its initial HTML.
React will return an HTML string.
You can use this method to generate HTML on the server and send the markup down on the initial request for faster page loads and to allow search engines to crawl your pages for SEO purposes.
If you call ReactDOM.hydrate()
on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience.
renderToStaticMarkup()
ReactDOMServer.renderToStaticMarkup(element)
Similar to renderToString
, except this doesn't create extra DOM attributes that React uses internally, such as data-reactroot
.
This is useful if you want to use React as a simple static page generator, as stripping away the extra attributes can save some bytes.
If you plan to use React on the client to make the markup interactive, do not use this method.
Instead, use renderToString
on the server and ReactDOM.hydrate()
on the client.
renderToNodeStream()
ReactDOMServer.renderToNodeStream(element)
Render a React element to its initial HTML.
Returns a Readable stream that outputs an HTML string.
The HTML output by this stream is exactly equal to what ReactDOMServer.renderToString
would return.
You can use this method to generate HTML on the server and send the markup down on the initial request for faster page loads and to allow search engines to crawl your pages for SEO purposes.
If you call ReactDOM.hydrate()
on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience.
Note:
Server-only.
This API is not available in the browser.
The stream returned from this method will return a byte stream encoded in utf-8.
If you need a stream in another encoding, take a look at a project like iconv-lite, which provides transform streams for transcoding text.
renderToStaticNodeStream()
ReactDOMServer.renderToStaticNodeStream(element)
Similar to renderToNodeStream
, except this doesn't create extra DOM attributes that React uses internally, such as data-reactroot
.
This is useful if you want to use React as a simple static page generator, as stripping away the extra attributes can save some bytes.
The HTML output by this stream is exactly equal to what ReactDOMServer.renderToStaticMarkup
would return.
If you plan to use React on the client to make the markup interactive, do not use this method.
Instead, use renderToNodeStream
on the server and ReactDOM.hydrate()
on the client.
Note:
Server-only.
This API is not available in the browser.
The stream returned from this method will return a byte stream encoded in utf-8.
If you need a stream in another encoding, take a look at a project like iconv-lite, which provides transform streams for transcoding text.
DOM Elements
React implements a browser-independent DOM system for performance and cross-browser compatibility.
We took the opportunity to clean up a few rough edges in browser DOM implementations.
In React, all DOM properties and attributes (including event handlers) should be camelCased.
For example, the HTML attribute tabindex
corresponds to the attribute tabIndex
in React.
The exception is aria-*
and data-*
attributes, which should be lowercased.
For example, you can keep aria-label
as aria-label
.
Differences In Attributes
There are a number of attributes that work differently between React and HTML:
checked
The checked
attribute is supported by <input>
components of type checkbox
or radio
.
You can use it to set whether the component is checked.
This is useful for building controlled components.
defaultChecked
is the uncontrolled equivalent, which sets whether the component is checked when it is first mounted.
className
To specify a CSS class, use the className
attribute.
This applies to all regular DOM and SVG elements like <div>
, <a>
, and others.
If you use React with Web Components (which is uncommon), use the class
attribute instead.
dangerouslySetInnerHTML
dangerouslySetInnerHTML
is React's replacement for using innerHTML
in the browser DOM.
In general, setting HTML from code is risky because it's easy to inadvertently expose your users to a cross-site scripting (XSS) attack.
So, you can set HTML directly from React, but you have to type out dangerouslySetInnerHTML
and pass an object with a __html
key, to remind yourself that it's dangerous.
For example:
function createMarkup() {
return {__html: 'First · Second'};
}
function MyComponent() {
return <div dangerouslySetInnerHTML={createMarkup()} />;
}
htmlFor
Since for
is a reserved word in JavaScript, React elements use htmlFor
instead.
onChange
The onChange
event behaves as you would expect it to: whenever a form field is changed, this event is fired.
We intentionally do not use the existing browser behavior because onChange
is a misnomer for its behavior and React relies on this event to handle user input in real time.
selected
If you want to mark an <option>
as selected, reference the value of that option in the value
of its <select>
instead.
Check out ¡°The select Tag¡± for detailed instructions.
style
Note
Some examples in the documentation use style
for convenience, but using the style
attribute as the primary means of styling elements is generally not recommended. In most cases, className
should be used to reference classes defined in an external CSS stylesheet.
style
is most often used in React applications to add dynamically-computed styles at render time.
See also FAQ: Styling and CSS.
The style
attribute accepts a JavaScript object with camelCased properties rather than a CSS string.
This is consistent with the DOM style
JavaScript property, is more efficient, and prevents XSS security holes.
For example:
const divStyle = {
color: 'blue',
backgroundImage: 'url(' + imgUrl + ')',
};
function HelloWorldComponent() {
return <div style={divStyle}>Hello World!</div>;
}
Note that styles are not autoprefixed.
To support older browsers, you need to supply corresponding style properties:
const divStyle = {
WebkitTransition: 'all', // note the capital 'W' here
msTransition: 'all' // 'ms' is the only lowercase vendor prefix
};
function ComponentWithTransition() {
return <div style={divStyle}>This should work cross-browser</div>;
}
Style keys are camelCased in order to be consistent with accessing the properties on DOM nodes from JS (e.g.
node.style.backgroundImage
).
Vendor prefixes other than ms
should begin with a capital letter.
This is why WebkitTransition
has an uppercase ¡°W¡±.
React will automatically append a ¡°px¡± suffix to certain numeric inline style properties.
If you want to use units other than ¡°px¡±, specify the value as a string with the desired unit.
For example:
// Result style: '10px'
<div style={{ height: 10 }}>
Hello World!
</div>
// Result style: '10%'
<div style={{ height: '10%' }}>
Hello World!
</div>
Not all style properties are converted to pixel strings though.
Certain ones remain unitless (eg zoom
, order
, flex
).
A complete list of unitless properties can be seen here.
suppressContentEditableWarning
Normally, there is a warning when an element with children is also marked as contentEditable
, because it won't work.
This attribute suppresses that warning.
Don't use this unless you are building a library like Draft.js that manages contentEditable
manually.
suppressHydrationWarning
If you use server-side React rendering, normally there is a warning when the server and the client render different content.
However, in some rare cases, it is very hard or impossible to guarantee an exact match.
For example, timestamps are expected to differ on the server and on the client.
If you set suppressHydrationWarning
to true
, React will not warn you about mismatches in the attributes and the content of that element.
It only works one level deep, and is intended to be used as an escape hatch.
Don't overuse it.
You can read more about hydration in the ReactDOM.hydrate()
documentation.
value
The value
attribute is supported by <input>
, <select>
and <textarea>
components.
You can use it to set the value of the component.
This is useful for building controlled components.
defaultValue
is the uncontrolled equivalent, which sets the value of the component when it is first mounted.
All Supported HTML Attributes
As of React 16, any standard or custom DOM attributes are fully supported.
React has always provided a JavaScript-centric API to the DOM.
Since React components often take both custom and DOM-related props, React uses the camelCase
convention just like the DOM APIs:
<div tabIndex={-1} /> // Just like node.tabIndex DOM API
<div className="Button" /> // Just like node.className DOM API
<input readOnly={true} /> // Just like node.readOnly DOM API
These props work similarly to the corresponding HTML attributes, with the exception of the special cases documented above.
Some of the DOM attributes supported by React include:
accept acceptCharset accessKey action allowFullScreen alt async autoComplete
autoFocus autoPlay capture cellPadding cellSpacing challenge charSet checked
cite classID className colSpan cols content contentEditable contextMenu controls
controlsList coords crossOrigin data dateTime default defer dir disabled
download draggable encType form formAction formEncType formMethod formNoValidate
formTarget frameBorder headers height hidden high href hrefLang htmlFor
httpEquiv icon id inputMode integrity is keyParams keyType kind label lang list
loop low manifest marginHeight marginWidth max maxLength media mediaGroup method
min minLength multiple muted name noValidate nonce open optimum pattern
placeholder poster preload profile radioGroup readOnly rel required reversed
role rowSpan rows sandbox scope scoped scrolling seamless selected shape size
sizes span spellCheck src srcDoc srcLang srcSet start step style summary
tabIndex target title type useMap value width wmode wrap
Similarly, all SVG attributes are fully supported:
accentHeight accumulate additive alignmentBaseline allowReorder alphabetic
amplitude arabicForm ascent attributeName attributeType autoReverse azimuth
baseFrequency baseProfile baselineShift bbox begin bias by calcMode capHeight
clip clipPath clipPathUnits clipRule colorInterpolation
colorInterpolationFilters colorProfile colorRendering contentScriptType
contentStyleType cursor cx cy d decelerate descent diffuseConstant direction
display divisor dominantBaseline dur dx dy edgeMode elevation enableBackground
end exponent externalResourcesRequired fill fillOpacity fillRule filter
filterRes filterUnits floodColor floodOpacity focusable fontFamily fontSize
fontSizeAdjust fontStretch fontStyle fontVariant fontWeight format from fx fy
g1 g2 glyphName glyphOrientationHorizontal glyphOrientationVertical glyphRef
gradientTransform gradientUnits hanging horizAdvX horizOriginX ideographic
imageRendering in in2 intercept k k1 k2 k3 k4 kernelMatrix kernelUnitLength
kerning keyPoints keySplines keyTimes lengthAdjust letterSpacing lightingColor
limitingConeAngle local markerEnd markerHeight markerMid markerStart
markerUnits markerWidth mask maskContentUnits maskUnits mathematical mode
numOctaves offset opacity operator order orient orientation origin overflow
overlinePosition overlineThickness paintOrder panose1 pathLength
patternContentUnits patternTransform patternUnits pointerEvents points
pointsAtX pointsAtY pointsAtZ preserveAlpha preserveAspectRatio primitiveUnits
r radius refX refY renderingIntent repeatCount repeatDur requiredExtensions
requiredFeatures restart result rotate rx ry scale seed shapeRendering slope
spacing specularConstant specularExponent speed spreadMethod startOffset
stdDeviation stemh stemv stitchTiles stopColor stopOpacity
strikethroughPosition strikethroughThickness string stroke strokeDasharray
strokeDashoffset strokeLinecap strokeLinejoin strokeMiterlimit strokeOpacity
strokeWidth surfaceScale systemLanguage tableValues targetX targetY textAnchor
textDecoration textLength textRendering to transform u1 u2 underlinePosition
underlineThickness unicode unicodeBidi unicodeRange unitsPerEm vAlphabetic
vHanging vIdeographic vMathematical values vectorEffect version vertAdvY
vertOriginX vertOriginY viewBox viewTarget visibility widths wordSpacing
writingMode x x1 x2 xChannelSelector xHeight xlinkActuate xlinkArcrole
xlinkHref xlinkRole xlinkShow xlinkTitle xlinkType xmlns xmlnsXlink xmlBase
xmlLang xmlSpace y y1 y2 yChannelSelector z zoomAndPan
You may also use custom attributes as long as they're fully lowercase.
SyntheticEvent
This reference guide documents the SyntheticEvent
wrapper that forms part of React's Event System.
See the Handling Events guide to learn more.
Overview
Your event handlers will be passed instances of SyntheticEvent
, a cross-browser wrapper around the browser's native event.
It has the same interface as the browser's native event, including stopPropagation()
and preventDefault()
, except the events work identically across all browsers.
If you find that you need the underlying browser event for some reason, simply use the nativeEvent
attribute to get it.
The synthetic events are different from, and do not map directly to, the browser's native events.
For example in onMouseLeave
event.nativeEvent
will point to a mouseout
event.
The specific mapping is not part of the public API and may change at any time.
Every SyntheticEvent
object has the following attributes:
boolean bubbles
boolean cancelable
DOMEventTarget currentTarget
boolean defaultPrevented
number eventPhase
boolean isTrusted
DOMEvent nativeEvent
void preventDefault()
boolean isDefaultPrevented()
void stopPropagation()
boolean isPropagationStopped()
void persist()
DOMEventTarget target
number timeStamp
string type
Note:
As of v17, e.persist()
doesn't do anything because the SyntheticEvent
is no longer pooled.
Note:
As of v0.14, returning false
from an event handler will no longer stop event propagation.
Instead, e.stopPropagation()
or e.preventDefault()
should be triggered manually, as appropriate.
Supported Events
React normalizes events so that they have consistent properties across different browsers.
The event handlers below are triggered by an event in the bubbling phase.
To register an event handler for the capture phase, append Capture
to the event name; for example, instead of using onClick
, you would use onClickCapture
to handle the click event in the capture phase.
- Clipboard Events
- Composition Events
- Keyboard Events
- Focus Events
- Form Events
- Generic Events
- Mouse Events
- Pointer Events
- Selection Events
- Touch Events
- UI Events
- Wheel Events
- Media Events
- Image Events
- Animation Events
- Transition Events
- Other Events
Reference
Clipboard Events
Event names:
onCopy onCut onPaste
Properties:
DOMDataTransfer clipboardData
Composition Events
Event names:
onCompositionEnd onCompositionStart onCompositionUpdate
Properties:
string data
Keyboard Events
Event names:
onKeyDown onKeyPress onKeyUp
Properties:
boolean altKey
number charCode
boolean ctrlKey
boolean getModifierState(key)
string key
number keyCode
string locale
number location
boolean metaKey
boolean repeat
boolean shiftKey
number which
The key
property can take any of the values documented in the DOM Level 3 Events spec.
Focus Events
Event names:
onFocus onBlur
These focus events work on all elements in the React DOM, not just form elements.
Properties:
DOMEventTarget relatedTarget
onFocus
The onFocus
event is called when the element (or some element inside of it) receives focus.
For example, it's called when the user clicks on a text input.
function Example() {
return (
<input
onFocus={(e) => {
console.log('Focused on input');
}}
placeholder="onFocus is triggered when you click this input."
/>
)
}
onBlur
The onBlur
event handler is called when focus has left the element (or left some element inside of it).
For example, it's called when the user clicks outside of a focused text input.
function Example() {
return (
<input
onBlur={(e) => {
console.log('Triggered because this input lost focus');
}}
placeholder="onBlur is triggered when you click this input and then you click outside of it."
/>
)
}
Detecting Focus Entering and Leaving
You can use the currentTarget
and relatedTarget
to differentiate if the focusing or blurring events originated from outside of the parent element.
Here is a demo you can copy and paste that shows how to detect focusing a child, focusing the element itself, and focus entering or leaving the whole subtree.
function Example() {
return (
<div
tabIndex={1}
onFocus={(e) => {
if (e.currentTarget === e.target) {
console.log('focused self');
} else {
console.log('focused child', e.target);
}
if (!e.currentTarget.contains(e.relatedTarget)) {
// Not triggered when swapping focus between children
console.log('focus entered self');
}
}}
onBlur={(e) => {
if (e.currentTarget === e.target) {
console.log('unfocused self');
} else {
console.log('unfocused child', e.target);
}
if (!e.currentTarget.contains(e.relatedTarget)) {
// Not triggered when swapping focus between children
console.log('focus left self');
}
}}
>
<input id="1" />
<input id="2" />
</div>
);
}
Form Events
Event names:
onChange onInput onInvalid onReset onSubmit
For more information about the onChange event, see Forms.
Generic Events
Event names:
onError onLoad
Mouse Events
Event names:
onClick onContextMenu onDoubleClick onDrag onDragEnd onDragEnter onDragExit
onDragLeave onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave
onMouseMove onMouseOut onMouseOver onMouseUp
The onMouseEnter
and onMouseLeave
events propagate from the element being left to the one being entered instead of ordinary bubbling and do not have a capture phase.
Properties:
boolean altKey
number button
number buttons
number clientX
number clientY
boolean ctrlKey
boolean getModifierState(key)
boolean metaKey
number pageX
number pageY
DOMEventTarget relatedTarget
number screenX
number screenY
boolean shiftKey
Pointer Events
Event names:
onPointerDown onPointerMove onPointerUp onPointerCancel onGotPointerCapture
onLostPointerCapture onPointerEnter onPointerLeave onPointerOver onPointerOut
The onPointerEnter
and onPointerLeave
events propagate from the element being left to the one being entered instead of ordinary bubbling and do not have a capture phase.
Properties:
As defined in the W3 spec, pointer events extend Mouse Events with the following properties:
number pointerId
number width
number height
number pressure
number tangentialPressure
number tiltX
number tiltY
number twist
string pointerType
boolean isPrimary
A note on cross-browser support:
Pointer events are not yet supported in every browser (at the time of writing this article, supported browsers include: Chrome, Firefox, Edge, and Internet Explorer).
React deliberately does not polyfill support for other browsers because a standard-conform polyfill would significantly increase the bundle size of react-dom
.
If your application requires pointer events, we recommend adding a third party pointer event polyfill.
Selection Events
Event names:
onSelect
Touch Events
Event names:
onTouchCancel onTouchEnd onTouchMove onTouchStart
Properties:
boolean altKey
DOMTouchList changedTouches
boolean ctrlKey
boolean getModifierState(key)
boolean metaKey
boolean shiftKey
DOMTouchList targetTouches
DOMTouchList touches
UI Events
Event names:
onScroll
Note
Starting with React 17, the onScroll
event does not bubble in React.
This matches the browser behavior and prevents the confusion when a nested scrollable element fires events on a distant parent.
Properties:
number detail
DOMAbstractView view
Wheel Events
Event names:
onWheel
Properties:
number deltaMode
number deltaX
number deltaY
number deltaZ
Media Events
Event names:
onAbort onCanPlay onCanPlayThrough onDurationChange onEmptied onEncrypted
onEnded onError onLoadedData onLoadedMetadata onLoadStart onPause onPlay
onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend
onTimeUpdate onVolumeChange onWaiting
Image Events
Event names:
onLoad onError
Animation Events
Event names:
onAnimationStart onAnimationEnd onAnimationIteration
Properties:
string animationName
string pseudoElement
float elapsedTime
Transition Events
Event names:
onTransitionEnd
Properties:
string propertyName
string pseudoElement
float elapsedTime
Other Events
Event names:
onToggle
Test Utilities
Importing
import ReactTestUtils from 'react-dom/test-utils'; // ES6
var ReactTestUtils = require('react-dom/test-utils'); // ES5 with npm
Overview
ReactTestUtils
makes it easy to test React components in the testing framework of your choice.
At Facebook we use Jest for painless JavaScript testing.
Learn how to get started with Jest through the Jest website's React Tutorial.
Note:
We recommend using React Testing Library which is designed to enable and encourage writing tests that use your components as the end users do.
Alternatively, Airbnb has released a testing utility called Enzyme, which makes it easy to assert, manipulate, and traverse your React Components' output.
act()
mockComponent()
isElement()
isElementOfType()
isDOMComponent()
isCompositeComponent()
isCompositeComponentWithType()
findAllInRenderedTree()
scryRenderedDOMComponentsWithClass()
findRenderedDOMComponentWithClass()
scryRenderedDOMComponentsWithTag()
findRenderedDOMComponentWithTag()
scryRenderedComponentsWithType()
findRenderedComponentWithType()
renderIntoDocument()
Simulate
Reference
act()
To prepare a component for assertions, wrap the code rendering it and performing updates inside an act()
call.
This makes your test run closer to how React works in the browser.
Note
If you use react-test-renderer
, it also provides an act
export that behaves the same way.
For example, let's say we have this Counter
component:
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {count: 0};
this.handleClick = this.handleClick.bind(this);
}
componentDidMount() {
document.title = `You clicked ${this.state.count} times`;
}
componentDidUpdate() {
document.title = `You clicked ${this.state.count} times`;
}
handleClick() {
this.setState(state => ({
count: state.count + 1,
}));
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={this.handleClick}>
Click me
</button>
</div>
);
}
}
Here is how we can test it:
import React from 'react';
import ReactDOM from 'react-dom';
import { act } from 'react-dom/test-utils';import Counter from './Counter';
let container;
beforeEach(() => {
container = document.createElement('div');
document.body.appendChild(container);
});
afterEach(() => {
document.body.removeChild(container);
container = null;
});
it('can render and update a counter', () => {
// Test first render and componentDidMount
act(() => { ReactDOM.render(<Counter />, container); }); const button = container.querySelector('button');
const label = container.querySelector('p');
expect(label.textContent).toBe('You clicked 0 times');
expect(document.title).toBe('You clicked 0 times');
// Test second render and componentDidUpdate
act(() => { button.dispatchEvent(new MouseEvent('click', {bubbles: true})); }); expect(label.textContent).toBe('You clicked 1 times');
expect(document.title).toBe('You clicked 1 times');
});
- Don't forget that dispatching DOM events only works when the DOM container is added to the
document
.
You can use a library like React Testing Library to reduce the boilerplate code.
- The
recipes
document contains more details on how act()
behaves, with examples and usage.
mockComponent()
mockComponent(
componentClass,
[mockTagName]
)
Pass a mocked component module to this method to augment it with useful methods that allow it to be used as a dummy React component.
Instead of rendering as usual, the component will become a simple <div>
(or other tag if mockTagName
is provided) containing any provided children.
Note:
mockComponent()
is a legacy API.
We recommend using jest.mock()
instead.
isElement()
isElement(element)
Returns true
if element
is any React element.
isElementOfType()
isElementOfType(
element,
componentClass
)
Returns true
if element
is a React element whose type is of a React componentClass
.
isDOMComponent()
isDOMComponent(instance)
Returns true
if instance
is a DOM component (such as a <div>
or <span>
).
isCompositeComponent()
isCompositeComponent(instance)
Returns true
if instance
is a user-defined component, such as a class or a function.
isCompositeComponentWithType()
isCompositeComponentWithType(
instance,
componentClass
)
Returns true
if instance
is a component whose type is of a React componentClass
.
findAllInRenderedTree()
findAllInRenderedTree(
tree,
test
)
Traverse all components in tree
and accumulate all components where test(component)
is true
.
This is not that useful on its own, but it's used as a primitive for other test utils.
scryRenderedDOMComponentsWithClass()
scryRenderedDOMComponentsWithClass(
tree,
className
)
Finds all DOM elements of components in the rendered tree that are DOM components with the class name matching className
.
findRenderedDOMComponentWithClass()
findRenderedDOMComponentWithClass(
tree,
className
)
Like scryRenderedDOMComponentsWithClass()
but expects there to be one result, and returns that one result, or throws exception if there is any other number of matches besides one.
scryRenderedDOMComponentsWithTag()
scryRenderedDOMComponentsWithTag(
tree,
tagName
)
Finds all DOM elements of components in the rendered tree that are DOM components with the tag name matching tagName
.
findRenderedDOMComponentWithTag()
findRenderedDOMComponentWithTag(
tree,
tagName
)
Like scryRenderedDOMComponentsWithTag()
but expects there to be one result, and returns that one result, or throws exception if there is any other number of matches besides one.
scryRenderedComponentsWithType()
scryRenderedComponentsWithType(
tree,
componentClass
)
Finds all instances of components with type equal to componentClass
.
findRenderedComponentWithType()
findRenderedComponentWithType(
tree,
componentClass
)
Same as scryRenderedComponentsWithType()
but expects there to be one result and returns that one result, or throws exception if there is any other number of matches besides one.
renderIntoDocument()
renderIntoDocument(element)
Render a React element into a detached DOM node in the document.
This function requires a DOM. It is effectively equivalent to:
const domContainer = document.createElement('div');
ReactDOM.render(element, domContainer);
Note:
You will need to have window
, window.document
and window.document.createElement
globally available before you import React
.
Otherwise React will think it can't access the DOM and methods like setState
won't work.
Other Utilities
Simulate
Simulate.{eventName}(
element,
[eventData]
)
Simulate an event dispatch on a DOM node with optional eventData
event data.
Simulate
has a method for every event that React understands.
Clicking an element
// <button ref={(node) => this.button = node}>...</button>
const node = this.button;
ReactTestUtils.Simulate.click(node);
Changing the value of an input field and then pressing ENTER.
// <input ref={(node) => this.textInput = node} />
const node = this.textInput;
node.value = 'giraffe';
ReactTestUtils.Simulate.change(node);
ReactTestUtils.Simulate.keyDown(node, {key: "Enter", keyCode: 13, which: 13});
Note
You will have to provide any event property that you're using in your component (e.g.
keyCode, which, etc¡) as React is not creating any of these for you.
Test Renderer
Importing
import TestRenderer from 'react-test-renderer'; // ES6
const TestRenderer = require('react-test-renderer'); // ES5 with npm
Overview
This package provides a React renderer that can be used to render React components to pure JavaScript objects, without depending on the DOM or a native mobile environment.
Essentially, this package makes it easy to grab a snapshot of the platform view hierarchy (similar to a DOM tree) rendered by a React DOM or React Native component without using a browser or jsdom.
Example:
import TestRenderer from 'react-test-renderer';
function Link(props) {
return <a href={props.page}>{props.children}</a>;
}
const testRenderer = TestRenderer.create(
<Link page="https://www.facebook.com/">Facebook</Link>
);
console.log(testRenderer.toJSON());
// { type: 'a',
// props: { href: 'https://www.facebook.com/' },
// children: [ 'Facebook' ] }
You can use Jest's snapshot testing feature to automatically save a copy of the JSON tree to a file and check in your tests that it hasn't changed: Learn more about it.
You can also traverse the output to find specific nodes and make assertions about them.
import TestRenderer from 'react-test-renderer';
function MyComponent() {
return (
<div>
<SubComponent foo="bar" />
<p className="my">Hello</p>
</div>
)
}
function SubComponent() {
return (
<p className="sub">Sub</p>
);
}
const testRenderer = TestRenderer.create(<MyComponent />);
const testInstance = testRenderer.root;
expect(testInstance.findByType(SubComponent).props.foo).toBe('bar');
expect(testInstance.findByProps({className: "sub"}).children).toEqual(['Sub']);
TestRenderer
TestRenderer.create()
TestRenderer.act()
TestRenderer instance
testRenderer.toJSON()
testRenderer.toTree()
testRenderer.update()
testRenderer.unmount()
testRenderer.getInstance()
testRenderer.root
TestInstance
testInstance.find()
testInstance.findByType()
testInstance.findByProps()
testInstance.findAll()
testInstance.findAllByType()
testInstance.findAllByProps()
testInstance.instance
testInstance.type
testInstance.props
testInstance.parent
testInstance.children
Reference
TestRenderer.create()
TestRenderer.create(element, options);
Create a TestRenderer
instance with the passed React element.
It doesn't use the real DOM, but it still fully renders the component tree into memory so you can make assertions about it.
Returns a TestRenderer instance.
TestRenderer.act()
TestRenderer.act(callback);
Similar to the act()
helper from react-dom/test-utils
, TestRenderer.act
prepares a component for assertions.
Use this version of act()
to wrap calls to TestRenderer.create
and testRenderer.update
.
import {create, act} from 'react-test-renderer';
import App from './app.js'; // The component being tested
// render the component
let root;
act(() => {
root = create(<App value={1}/>)
});
// make assertions on root
expect(root.toJSON()).toMatchSnapshot();
// update with some different props
act(() => {
root.update(<App value={2}/>);
})
// make assertions on root
expect(root.toJSON()).toMatchSnapshot();
testRenderer.toJSON()
testRenderer.toJSON()
Return an object representing the rendered tree.
This tree only contains the platform-specific nodes like <div>
or <View>
and their props, but doesn't contain any user-written components.
This is handy for snapshot testing.
testRenderer.toTree()
testRenderer.toTree()
Return an object representing the rendered tree.
The representation is more detailed than the one provided by toJSON()
, and includes the user-written components.
You probably don't need this method unless you're writing your own assertion library on top of the test renderer.
testRenderer.update()
testRenderer.update(element)
Re-render the in-memory tree with a new root element.
This simulates a React update at the root.
If the new element has the same type and key as the previous element, the tree will be updated; otherwise, it will re-mount a new tree.
testRenderer.unmount()
testRenderer.unmount()
Unmount the in-memory tree, triggering the appropriate lifecycle events.
testRenderer.getInstance()
testRenderer.getInstance()
Return the instance corresponding to the root element, if available.
This will not work if the root element is a function component because they don't have instances.
testRenderer.root
testRenderer.root
Returns the root ¡°test instance¡± object that is useful for making assertions about specific nodes in the tree.
You can use it to find other ¡°test instances¡± deeper below.
testInstance.find()
testInstance.find(test)
Find a single descendant test instance for which test(testInstance)
returns true
.
If test(testInstance)
does not return true
for exactly one test instance, it will throw an error.
testInstance.findByType()
testInstance.findByType(type)
Find a single descendant test instance with the provided type
.
If there is not exactly one test instance with the provided type
, it will throw an error.
testInstance.findByProps()
testInstance.findByProps(props)
Find a single descendant test instance with the provided props
.
If there is not exactly one test instance with the provided props
, it will throw an error.
testInstance.findAll()
testInstance.findAll(test)
Find all descendant test instances for which test(testInstance)
returns true
.
testInstance.findAllByType()
testInstance.findAllByType(type)
Find all descendant test instances with the provided type
.
testInstance.findAllByProps()
testInstance.findAllByProps(props)
Find all descendant test instances with the provided props
.
testInstance.instance
testInstance.instance
The component instance corresponding to this test instance.
It is only available for class components, as function components don't have instances.
It matches the this
value inside the given component.
testInstance.type
testInstance.type
The component type corresponding to this test instance.
For example, a <Button />
component has a type of Button
.
testInstance.props
testInstance.props
The props corresponding to this test instance.
For example, a <Button size="small" />
component has {size: 'small'}
as props.
testInstance.parent
testInstance.parent
The parent test instance of this test instance.
testInstance.children
testInstance.children
The children test instances of this test instance.
Ideas
You can pass createNodeMock
function to TestRenderer.create
as the option, which allows for custom mock refs.
createNodeMock
accepts the current element and should return a mock ref object.
This is useful when you test a component that relies on refs.
import TestRenderer from 'react-test-renderer';
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.input = null;
}
componentDidMount() {
this.input.focus();
}
render() {
return <input type="text" ref={el => this.input = el} />
}
}
let focused = false;
TestRenderer.create(
<MyComponent />,
{
createNodeMock: (element) => {
if (element.type === 'input') {
// mock a focus function
return {
focus: () => {
focused = true;
}
};
}
return null;
}
}
);
expect(focused).toBe(true);
JavaScript Environment Requirements
React 16 depends on the collection types Map and Set.
If you support older browsers and devices which may not yet provide these natively (e.g.
IE < 11) or which have non-compliant implementations (e.g.
IE 11), consider including a global polyfill in your bundled application, such as core-js.
A polyfilled environment for React 16 using core-js to support older browsers might look like:
import 'core-js/es/map';
import 'core-js/es/set';
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(
<h2>Hello, world!</h2>,
document.getElementById('root')
);
React also depends on requestAnimationFrame
(even in test environments).
You can use the raf package to shim requestAnimationFrame
:
import 'raf/polyfill';
Glossary of React Terms
Single-page Application
A single-page application is an application that loads a single HTML page and all the necessary assets (such as JavaScript and CSS) required for the application to run.
Any interactions with the page or subsequent pages do not require a round trip to the server which means the page is not reloaded.
Though you may build a single-page application in React, it is not a requirement.
React can also be used for enhancing small parts of existing websites with additional interactivity.
Code written in React can coexist peacefully with markup rendered on the server by something like PHP, or with other client-side libraries.
In fact, this is exactly how React is being used at Facebook.
ES6, ES2015, ES2016, etc
These acronyms all refer to the most recent versions of the ECMAScript Language Specification standard, which the JavaScript language is an implementation of.
The ES6 version (also known as ES2015) includes many additions to the previous versions such as: arrow functions, classes, template literals, let
and const
statements.
You can learn more about specific versions here.
Compilers
A JavaScript compiler takes JavaScript code, transforms it and returns JavaScript code in a different format.
The most common use case is to take ES6 syntax and transform it into syntax that older browsers are capable of interpreting.
Babel is the compiler most commonly used with React.
Bundlers
Bundlers take JavaScript and CSS code written as separate modules (often hundreds of them), and combine them together into a few files better optimized for the browsers.
Some bundlers commonly used in React applications include Webpack and Browserify.
Package Managers
Package managers are tools that allow you to manage dependencies in your project.
npm and Yarn are two package managers commonly used in React applications.
Both of them are clients for the same npm package registry.
CDN
CDN stands for Content Delivery Network.
CDNs deliver cached, static content from a network of servers across the globe.
JSX
JSX is a syntax extension to JavaScript.
It is similar to a template language, but it has full power of JavaScript.
JSX gets compiled to React.createElement()
calls which return plain JavaScript objects called ¡°React elements¡±.
To get a basic introduction to JSX see the docs here and find a more in-depth tutorial on JSX here.
React DOM uses camelCase property naming convention instead of HTML attribute names.
For example, tabindex
becomes tabIndex
in JSX.
The attribute class
is also written as className
since class
is a reserved word in JavaScript:
const name = 'Clementine';
ReactDOM.render(
<h2 className="hello">My name is {name}!</h2>,
document.getElementById('root')
);
Elements
React elements are the building blocks of React applications.
One might confuse elements with a more widely known concept of ¡°components¡±.
An element describes what you want to see on the screen.
React elements are immutable.
const element = <h2>Hello, world</h2>;
Typically, elements are not used directly, but get returned from components.
Components
React components are small, reusable pieces of code that return a React element to be rendered to the page.
The simplest version of React component is a plain JavaScript function that returns a React element:
function Welcome(props) {
return <h2>Hello, {props.name}</h2>;
}
Components can also be ES6 classes:
class Welcome extends React.Component {
render() {
return <h2>Hello, {this.props.name}</h2>;
}
}
Components can be broken down into distinct pieces of functionality and used within other components.
Components can return other components, arrays, strings and numbers.
A good rule of thumb is that if a part of your UI is used several times (Button, Panel, Avatar), or is complex enough on its own (App, FeedStory, Comment), it is a good candidate to be a reusable component.
Component names should also always start with a capital letter (<Wrapper/>
not <wrapper/>
).
See this documentation for more information on rendering components.
props
props
are inputs to a React component.
They are data passed down from a parent component to a child component.
Remember that props
are readonly.
They should not be modified in any way:
// Wrong!
props.number = 42;
If you need to modify some value in response to user input or a network response, use state
instead.
props.children
props.children
is available on every component.
It contains the content between the opening and closing tags of a component.
For example:
<Welcome>Hello world!</Welcome>
The string Hello world!
is available in props.children
in the Welcome
component:
function Welcome(props) {
return <p>{props.children}</p>;
}
For components defined as classes, use this.props.children
:
class Welcome extends React.Component {
render() {
return <p>{this.props.children}</p>;
}
}
state
A component needs state
when some data associated with it changes over time.
For example, a Checkbox
component might need isChecked
in its state, and a NewsFeed
component might want to keep track of fetchedPosts
in its state.
The most important difference between state
and props
is that props
are passed from a parent component, but state
is managed by the component itself.
A component cannot change its props
, but it can change its state
.
For each particular piece of changing data, there should be just one component that ¡°owns¡± it in its state.
Don't try to synchronize states of two different components.
Instead, lift it up to their closest shared ancestor, and pass it down as props to both of them.
Lifecycle Methods
Lifecycle methods are custom functionality that gets executed during the different phases of a component.
There are methods available when the component gets created and inserted into the DOM (mounting), when the component updates, and when the component gets unmounted or removed from the DOM.
Controlled vs.
Uncontrolled Components
React has two different approaches to dealing with form inputs.
An input form element whose value is controlled by React is called a controlled component.
When a user enters data into a controlled component a change event handler is triggered and your code decides whether the input is valid (by re-rendering with the updated value).
If you do not re-render then the form element will remain unchanged.
An uncontrolled component works like form elements do outside of React.
When a user inputs data into a form field (an input box, dropdown, etc) the updated information is reflected without React needing to do anything.
However, this also means that you can't force the field to have a certain value.
In most cases you should use controlled components.
Keys
A ¡°key¡± is a special string attribute you need to include when creating arrays of elements.
Keys help React identify which items have changed, are added, or are removed.
Keys should be given to the elements inside an array to give the elements a stable identity.
Keys only need to be unique among sibling elements in the same array.
They don't need to be unique across the whole application or even a single component.
Don't pass something like Math.random()
to keys.
It is important that keys have a ¡°stable identity¡± across re-renders so that React can determine when items are added, removed, or re-ordered.
Ideally, keys should correspond to unique and stable identifiers coming from your data, such as post.id
.
Refs
React supports a special attribute that you can attach to any component.
The ref
attribute can be an object created by React.createRef()
function or a callback function, or a string (in legacy API).
When the ref
attribute is a callback function, the function receives the underlying DOM element or class instance (depending on the type of element) as its argument.
This allows you to have direct access to the DOM element or component instance.
Use refs sparingly.
If you find yourself often using refs to ¡°make things happen¡± in your app, consider getting more familiar with top-down data flow.
Events
Handling events with React elements has some syntactic differences:
- React event handlers are named using camelCase, rather than lowercase.
- With JSX you pass a function as the event handler, rather than a string.
Reconciliation
When a component's props or state change, React decides whether an actual DOM update is necessary by comparing the newly returned element with the previously rendered one.
When they are not equal, React will update the DOM.
This process is called ¡°reconciliation¡±.
Introducing Hooks
Hooks are a new addition in React 16.8.
They let you use state and other React features without writing a class.
import React, { useState } from 'react';
function Example() {
// Declare a new state variable, which we'll call "count" const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
This new function useState
is the first ¡°Hook¡± we'll learn about, but this example is just a teaser.
Don't worry if it doesn't make sense yet!
You can start learning Hooks on the next page. On this page, we'll continue by explaining why we're adding Hooks to React and how they can help you write great applications.
Note
React 16.8.0 is the first release to support Hooks.
When upgrading, don't forget to update all packages, including React DOM.
React Native supports Hooks since the 0.59 release of React Native.
Video Introduction
At React Conf 2018, Sophie Alpert and Dan Abramov introduced Hooks, followed by Ryan Florence demonstrating how to refactor an application to use them.
Watch the video here:
No Breaking Changes
Before we continue, note that Hooks are:
-
Completely opt-in. You can try Hooks in a few components without rewriting any existing code.
But you don't have to learn or use Hooks right now if you don't want to.
-
100% backwards-compatible. Hooks don't contain any breaking changes.
-
Available now. Hooks are now available with the release of v16.8.0.
There are no plans to remove classes from React. You can read more about the gradual adoption strategy for Hooks in the bottom section of this page.
Hooks don't replace your knowledge of React concepts. Instead, Hooks provide a more direct API to the React concepts you already know: props, state, context, refs, and lifecycle.
As we will show later, Hooks also offer a new powerful way to combine them.
If you just want to start learning Hooks, feel free to jump directly to the next page! You can also keep reading this page to learn more about why we're adding Hooks, and how we're going to start using them without rewriting our applications.
Motivation
Hooks solve a wide variety of seemingly unconnected problems in React that we've encountered over five years of writing and maintaining tens of thousands of components.
Whether you're learning React, use it daily, or even prefer a different library with a similar component model, you might recognize some of these problems.
It's hard to reuse stateful logic between components
React doesn't offer a way to ¡°attach¡± reusable behavior to a component (for example, connecting it to a store).
If you've worked with React for a while, you may be familiar with patterns like render props and higher-order components that try to solve this.
But these patterns require you to restructure your components when you use them, which can be cumbersome and make code harder to follow.
If you look at a typical React application in React DevTools, you will likely find a ¡°wrapper hell¡± of components surrounded by layers of providers, consumers, higher-order components, render props, and other abstractions.
While we could filter them out in DevTools, this points to a deeper underlying problem: React needs a better primitive for sharing stateful logic.
With Hooks, you can extract stateful logic from a component so it can be tested independently and reused.
Hooks allow you to reuse stateful logic without changing your component hierarchy. This makes it easy to share Hooks among many components or with the community.
We'll discuss this more in Building Your Own Hooks.
Complex components become hard to understand
We've often had to maintain components that started out simple but grew into an unmanageable mess of stateful logic and side effects.
Each lifecycle method often contains a mix of unrelated logic.
For example, components might perform some data fetching in componentDidMount
and componentDidUpdate
.
However, the same componentDidMount
method might also contain some unrelated logic that sets up event listeners, with cleanup performed in componentWillUnmount
.
Mutually related code that changes together gets split apart, but completely unrelated code ends up combined in a single method.
This makes it too easy to introduce bugs and inconsistencies.
In many cases it's not possible to break these components into smaller ones because the stateful logic is all over the place.
It's also difficult to test them.
This is one of the reasons many people prefer to combine React with a separate state management library.
However, that often introduces too much abstraction, requires you to jump between different files, and makes reusing components more difficult.
To solve this, Hooks let you split one component into smaller functions based on what pieces are related (such as setting up a subscription or fetching data), rather than forcing a split based on lifecycle methods.
You may also opt into managing the component's local state with a reducer to make it more predictable.
We'll discuss this more in Using the Effect Hook.
Classes confuse both people and machines
In addition to making code reuse and code organization more difficult, we've found that classes can be a large barrier to learning React.
You have to understand how this
works in JavaScript, which is very different from how it works in most languages.
You have to remember to bind the event handlers.
Without unstable syntax proposals, the code is very verbose.
People can understand props, state, and top-down data flow perfectly well but still struggle with classes.
The distinction between function and class components in React and when to use each one leads to disagreements even between experienced React developers.
Additionally, React has been out for about five years, and we want to make sure it stays relevant in the next five years.
As Svelte, Angular, Glimmer, and others show, ahead-of-time compilation of components has a lot of future potential.
Especially if it's not limited to templates.
Recently, we've been experimenting with component folding using Prepack, and we've seen promising early results.
However, we found that class components can encourage unintentional patterns that make these optimizations fall back to a slower path.
Classes present issues for today's tools, too.
For example, classes don't minify very well, and they make hot reloading flaky and unreliable.
We want to present an API that makes it more likely for code to stay on the optimizable path.
To solve these problems, Hooks let you use more of React's features without classes. Conceptually, React components have always been closer to functions.
Hooks embrace functions, but without sacrificing the practical spirit of React.
Hooks provide access to imperative escape hatches and don't require you to learn complex functional or reactive programming techniques.
Examples
Hooks at a Glance is a good place to start learning Hooks.
Gradual Adoption Strategy
TLDR: There are no plans to remove classes from React.
We know that React developers are focused on shipping products and don't have time to look into every new API that's being released.
Hooks are very new, and it might be better to wait for more examples and tutorials before considering learning or adopting them.
We also understand that the bar for adding a new primitive to React is extremely high.
For curious readers, we have prepared a detailed RFC that dives into motivation with more details, and provides extra perspective on the specific design decisions and related prior art.
Crucially, Hooks work side-by-side with existing code so you can adopt them gradually. There is no rush to migrate to Hooks.
We recommend avoiding any ¡°big rewrites¡±, especially for existing, complex class components.
It takes a bit of a mindshift to start ¡°thinking in Hooks¡±.
In our experience, it's best to practice using Hooks in new and non-critical components first, and ensure that everybody on your team feels comfortable with them.
After you give Hooks a try, please feel free to send us feedback, positive or negative.
We intend for Hooks to cover all existing use cases for classes, but we will keep supporting class components for the foreseeable future. At Facebook, we have tens of thousands of components written as classes, and we have absolutely no plans to rewrite them.
Instead, we are starting to use Hooks in the new code side by side with classes.
Frequently Asked Questions
We've prepared a Hooks FAQ page that answers the most common questions about Hooks.
Next Steps
By the end of this page, you should have a rough idea of what problems Hooks are solving, but many details are probably unclear.
Don't worry! Let's now go to the next page where we start learning about Hooks by example.
Hooks at a Glance
Hooks are a new addition in React 16.8.
They let you use state and other React features without writing a class.
Hooks are backwards-compatible.
This page provides an overview of Hooks for experienced React users.
This is a fast-paced overview.
If you get confused, look for a yellow box like this:
Detailed Explanation
Read the Motivation to learn why we're introducing Hooks to React.
¡ü¡ü¡ü Each section ends with a yellow box like this. They link to detailed explanations.
State Hook
This example renders a counter.
When you click the button, it increments the value:
import React, { useState } from 'react';
function Example() {
// Declare a new state variable, which we'll call "count" const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
Here, useState
is a Hook (we'll talk about what this means in a moment).
We call it inside a function component to add some local state to it.
React will preserve this state between re-renders.
useState
returns a pair: the current state value and a function that lets you update it.
You can call this function from an event handler or somewhere else.
It's similar to this.setState
in a class, except it doesn't merge the old and new state together.
(We'll show an example comparing useState
to this.state
in Using the State Hook.)
The only argument to useState
is the initial state.
In the example above, it is 0
because our counter starts from zero.
Note that unlike this.state
, the state here doesn't have to be an object ¡ª although it can be if you want.
The initial state argument is only used during the first render.
Declaring multiple state variables
You can use the State Hook more than once in a single component:
function ExampleWithManyStates() {
// Declare multiple state variables!
const [age, setAge] = useState(42);
const [fruit, setFruit] = useState('banana');
const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
// ...
}
The array destructuring syntax lets us give different names to the state variables we declared by calling useState
.
These names aren't a part of the useState
API.
Instead, React assumes that if you call useState
many times, you do it in the same order during every render.
We'll come back to why this works and when this is useful later.
But what is a Hook?
Hooks are functions that let you ¡°hook into¡± React state and lifecycle features from function components.
Hooks don't work inside classes ¡ª they let you use React without classes.
(We don't recommend rewriting your existing components overnight but you can start using Hooks in the new ones if you'd like.)
React provides a few built-in Hooks like useState
.
You can also create your own Hooks to reuse stateful behavior between different components.
We'll look at the built-in Hooks first.
Detailed Explanation
You can learn more about the State Hook on a dedicated page: Using the State Hook.
Effect Hook
You've likely performed data fetching, subscriptions, or manually changing the DOM from React components before.
We call these operations ¡°side effects¡± (or ¡°effects¡± for short) because they can affect other components and can't be done during rendering.
The Effect Hook, useEffect
, adds the ability to perform side effects from a function component.
It serves the same purpose as componentDidMount
, componentDidUpdate
, and componentWillUnmount
in React classes, but unified into a single API.
(We'll show examples comparing useEffect
to these methods in Using the Effect Hook.)
For example, this component sets the document title after React updates the DOM:
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// Similar to componentDidMount and componentDidUpdate: useEffect(() => { // Update the document title using the browser API document.title = `You clicked ${count} times`; });
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
When you call useEffect
, you're telling React to run your ¡°effect¡± function after flushing changes to the DOM.
Effects are declared inside the component so they have access to its props and state.
By default, React runs the effects after every render ¡ª including the first render.
(We'll talk more about how this compares to class lifecycles in Using the Effect Hook.)
Effects may also optionally specify how to ¡°clean up¡± after them by returning a function.
For example, this component uses an effect to subscribe to a friend's online status, and cleans up by unsubscribing from it:
import React, { useState, useEffect } from 'react';
function FriendStatus(props) {
const [isOnline, setIsOnline] = useState(null);
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
useEffect(() => { ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; });
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
In this example, React would unsubscribe from our ChatAPI
when the component unmounts, as well as before re-running the effect due to a subsequent render.
(If you want, there's a way to tell React to skip re-subscribing if the props.friend.id
we passed to ChatAPI
didn't change.)
Just like with useState
, you can use more than a single effect in a component:
function FriendStatusWithCounter(props) {
const [count, setCount] = useState(0);
useEffect(() => { document.title = `You clicked ${count} times`;
});
const [isOnline, setIsOnline] = useState(null);
useEffect(() => { ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
// ...
Hooks let you organize side effects in a component by what pieces are related (such as adding and removing a subscription), rather than forcing a split based on lifecycle methods.
Detailed Explanation
You can learn more about useEffect
on a dedicated page: Using the Effect Hook.
Rules of Hooks
Hooks are JavaScript functions, but they impose two additional rules:
- Only call Hooks at the top level.
Don't call Hooks inside loops, conditions, or nested functions.
- Only call Hooks from React function components.
Don't call Hooks from regular JavaScript functions.
(There is just one other valid place to call Hooks ¡ª your own custom Hooks.
We'll learn about them in a moment.)
We provide a linter plugin to enforce these rules automatically.
We understand these rules might seem limiting or confusing at first, but they are essential to making Hooks work well.
Detailed Explanation
You can learn more about these rules on a dedicated page: Rules of Hooks.
Building Your Own Hooks
Sometimes, we want to reuse some stateful logic between components.
Traditionally, there were two popular solutions to this problem: higher-order components and render props.
Custom Hooks let you do this, but without adding more components to your tree.
Earlier on this page, we introduced a FriendStatus
component that calls the useState
and useEffect
Hooks to subscribe to a friend's online status.
Let's say we also want to reuse this subscription logic in another component.
First, we'll extract this logic into a custom Hook called useFriendStatus
:
import React, { useState, useEffect } from 'react';
function useFriendStatus(friendID) { const [isOnline, setIsOnline] = useState(null);
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
useEffect(() => {
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
};
});
return isOnline;
}
It takes friendID
as an argument, and returns whether our friend is online.
Now we can use it from both components:
function FriendStatus(props) {
const isOnline = useFriendStatus(props.friend.id);
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
function FriendListItem(props) {
const isOnline = useFriendStatus(props.friend.id);
return (
<li style={{ color: isOnline ? 'green' : 'black' }}>
{props.friend.name}
</li>
);
}
The state of each component is completely independent.
Hooks are a way to reuse stateful logic, not state itself.
In fact, each call to a Hook has a completely isolated state ¡ª so you can even use the same custom Hook twice in one component.
Custom Hooks are more of a convention than a feature.
If a function's name starts with ¡±use
¡± and it calls other Hooks, we say it is a custom Hook.
The useSomething
naming convention is how our linter plugin is able to find bugs in the code using Hooks.
You can write custom Hooks that cover a wide range of use cases like form handling, animation, declarative subscriptions, timers, and probably many more we haven't considered.
We are excited to see what custom Hooks the React community will come up with.
Detailed Explanation
You can learn more about custom Hooks on a dedicated page: Building Your Own Hooks.
Other Hooks
There are a few less commonly used built-in Hooks that you might find useful.
For example, useContext
lets you subscribe to React context without introducing nesting:
function Example() {
const locale = useContext(LocaleContext); const theme = useContext(ThemeContext); // ...
}
And useReducer
lets you manage local state of complex components with a reducer:
function Todos() {
const [todos, dispatch] = useReducer(todosReducer); // ...
Detailed Explanation
You can learn more about all the built-in Hooks on a dedicated page: Hooks API Reference.
Next Steps
Phew, that was fast! If some things didn't quite make sense or you'd like to learn more in detail, you can read the next pages, starting with the State Hook documentation.
You can also check out the Hooks API reference and the Hooks FAQ.
Finally, don't miss the introduction page which explains why we're adding Hooks and how we'll start using them side by side with classes ¡ª without rewriting our apps.
Using the State Hook
Hooks are a new addition in React 16.8.
They let you use state and other React features without writing a class.
The introduction page used this example to get familiar with Hooks:
import React, { useState } from 'react';
function Example() {
// Declare a new state variable, which we'll call "count" const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
We'll start learning about Hooks by comparing this code to an equivalent class example.
Equivalent Class Example
If you used classes in React before, this code should look familiar:
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
The state starts as { count: 0 }
, and we increment state.count
when the user clicks a button by calling this.setState()
.
We'll use snippets from this class throughout the page.
Note
You might be wondering why we're using a counter here instead of a more realistic example.
This is to help us focus on the API while we're still making our first steps with Hooks.
Hooks and Function Components
As a reminder, function components in React look like this:
const Example = (props) => {
// You can use Hooks here!
return <div />;
}
or this:
function Example(props) {
// You can use Hooks here!
return <div />;
}
You might have previously known these as ¡°stateless components¡±.
We're now introducing the ability to use React state from these, so we prefer the name ¡°function components¡±.
Hooks don't work inside classes.
But you can use them instead of writing classes.
What's a Hook?
Our new example starts by importing the useState
Hook from React:
import React, { useState } from 'react';
function Example() {
// ...
}
What is a Hook? A Hook is a special function that lets you ¡°hook into¡± React features.
For example, useState
is a Hook that lets you add React state to function components.
We'll learn other Hooks later.
When would I use a Hook? If you write a function component and realize you need to add some state to it, previously you had to convert it to a class.
Now you can use a Hook inside the existing function component.
We're going to do that right now!
Note:
There are some special rules about where you can and can't use Hooks within a component.
We'll learn them in Rules of Hooks.
Declaring a State Variable
In a class, we initialize the count
state to 0
by setting this.state
to { count: 0 }
in the constructor:
class Example extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 }; }
In a function component, we have no this
, so we can't assign or read this.state
.
Instead, we call the useState
Hook directly inside our component:
import React, { useState } from 'react';
function Example() {
// Declare a new state variable, which we'll call "count" const [count, setCount] = useState(0);
What does calling useState
do? It declares a ¡°state variable¡±.
Our variable is called count
but we could call it anything else, like banana
.
This is a way to ¡°preserve¡± some values between the function calls ¡ª useState
is a new way to use the exact same capabilities that this.state
provides in a class.
Normally, variables ¡°disappear¡± when the function exits but state variables are preserved by React.
What do we pass to useState
as an argument? The only argument to the useState()
Hook is the initial state.
Unlike with classes, the state doesn't have to be an object.
We can keep a number or a string if that's all we need.
In our example, we just want a number for how many times the user clicked, so pass 0
as initial state for our variable.
(If we wanted to store two different values in state, we would call useState()
twice.)
What does useState
return? It returns a pair of values: the current state and a function that updates it.
This is why we write const [count, setCount] = useState()
.
This is similar to this.state.count
and this.setState
in a class, except you get them in a pair.
If you're not familiar with the syntax we used, we'll come back to it at the bottom of this page.
Now that we know what the useState
Hook does, our example should make more sense:
import React, { useState } from 'react';
function Example() {
// Declare a new state variable, which we'll call "count" const [count, setCount] = useState(0);
We declare a state variable called count
, and set it to 0
.
React will remember its current value between re-renders, and provide the most recent one to our function.
If we want to update the current count
, we can call setCount
.
Note
You might be wondering: why is useState
not named createState
instead?
¡°Create¡± wouldn't be quite accurate because the state is only created the first time our component renders.
During the next renders, useState
gives us the current state.
Otherwise it wouldn't be ¡°state¡± at all! There's also a reason why Hook names always start with use
.
We'll learn why later in the Rules of Hooks.
Reading State
When we want to display the current count in a class, we read this.state.count
:
<p>You clicked {this.state.count} times</p>
In a function, we can use count
directly:
<p>You clicked {count} times</p>
Updating State
In a class, we need to call this.setState()
to update the count
state:
<button onClick={() => this.setState({ count: this.state.count + 1 })}> Click me
</button>
In a function, we already have setCount
and count
as variables so we don't need this
:
<button onClick={() => setCount(count + 1)}> Click me
</button>
Recap
Let's now recap what we learned line by line and check our understanding.
1: import React, { useState } from 'react'; 2:
3: function Example() {
4: const [count, setCount] = useState(0); 5:
6: return (
7: <div>
8: <p>You clicked {count} times</p>
9: <button onClick={() => setCount(count + 1)}>10: Click me
11: </button>
12: </div>
13: );
14: }
-
Line 1: We import the
useState
Hook from React.
It lets us keep local state in a function component.
-
Line 4: Inside the
Example
component, we declare a new state variable by calling the useState
Hook.
It returns a pair of values, to which we give names.
We're calling our variable count
because it holds the number of button clicks.
We initialize it to zero by passing 0
as the only useState
argument.
The second returned item is itself a function.
It lets us update the count
so we'll name it setCount
.
-
Line 9: When the user clicks, we call
setCount
with a new value.
React will then re-render the Example
component, passing the new count
value to it.
This might seem like a lot to take in at first.
Don't rush it! If you're lost in the explanation, look at the code above again and try to read it from top to bottom.
We promise that once you try to ¡°forget¡± how state works in classes, and look at this code with fresh eyes, it will make sense.
Tip: What Do Square Brackets Mean?
You might have noticed the square brackets when we declare a state variable:
const [count, setCount] = useState(0);
The names on the left aren't a part of the React API.
You can name your own state variables:
const [fruit, setFruit] = useState('banana');
This JavaScript syntax is called ¡°array destructuring¡±.
It means that we're making two new variables fruit
and setFruit
, where fruit
is set to the first value returned by useState
, and setFruit
is the second.
It is equivalent to this code:
var fruitStateVariable = useState('banana'); // Returns a pair
var fruit = fruitStateVariable[0]; // First item in a pair
var setFruit = fruitStateVariable[1]; // Second item in a pair
When we declare a state variable with useState
, it returns a pair ¡ª an array with two items.
The first item is the current value, and the second is a function that lets us update it.
Using [0]
and [1]
to access them is a bit confusing because they have a specific meaning.
This is why we use array destructuring instead.
Note
You might be curious how React knows which component useState
corresponds to since we're not passing anything like this
back to React.
We'll answer this question and many others in the FAQ section.
Tip: Using Multiple State Variables
Declaring state variables as a pair of [something, setSomething]
is also handy because it lets us give different names to different state variables if we want to use more than one:
function ExampleWithManyStates() {
// Declare multiple state variables!
const [age, setAge] = useState(42);
const [fruit, setFruit] = useState('banana');
const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
In the above component, we have age
, fruit
, and todos
as local variables, and we can update them individually:
function handleOrangeClick() {
// Similar to this.setState({ fruit: 'orange' })
setFruit('orange');
}
You don't have to use many state variables.
State variables can hold objects and arrays just fine, so you can still group related data together.
However, unlike this.setState
in a class, updating a state variable always replaces it instead of merging it.
We provide more recommendations on splitting independent state variables in the FAQ.
Next Steps
On this page we've learned about one of the Hooks provided by React, called useState
.
We're also sometimes going to refer to it as the ¡°State Hook¡±.
It lets us add local state to React function components ¡ª which we did for the first time ever!
We also learned a little bit more about what Hooks are.
Hooks are functions that let you ¡°hook into¡± React features from function components.
Their names always start with use
, and there are more Hooks we haven't seen yet.
Now let's continue by learning the next Hook: useEffect
. It lets you perform side effects in components, and is similar to lifecycle methods in classes.
Rules of Hooks
Hooks are a new addition in React 16.8.
They let you use state and other React features without writing a class.
Hooks are JavaScript functions, but you need to follow two rules when using them.
We provide a linter plugin to enforce these rules automatically:
Only Call Hooks at the Top Level
Don't call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function.
By following this rule, you ensure that Hooks are called in the same order each time a component renders.
That's what allows React to correctly preserve the state of Hooks between multiple useState
and useEffect
calls.
(If you're curious, we'll explain this in depth below.)
Only Call Hooks from React Functions
Don't call Hooks from regular JavaScript functions. Instead, you can:
- Call Hooks from React function components.
- Call Hooks from custom Hooks (we'll learn about them on the next page).
By following this rule, you ensure that all stateful logic in a component is clearly visible from its source code.
ESLint Plugin
We released an ESLint plugin called eslint-plugin-react-hooks
that enforces these two rules.
You can add this plugin to your project if you'd like to try it:
This plugin is included by default in Create React App.
npm install eslint-plugin-react-hooks --save-dev
// Your ESLint configuration
{
"plugins": [
// ...
"react-hooks"
],
"rules": {
// ...
"react-hooks/rules-of-hooks": "error", // Checks rules of Hooks
"react-hooks/exhaustive-deps": "warn" // Checks effect dependencies
}
}
You can skip to the next page explaining how to write your own Hooks now. On this page, we'll continue by explaining the reasoning behind these rules.
Explanation
As we learned earlier, we can use multiple State or Effect Hooks in a single component:
function Form() {
// 1.
Use the name state variable
const [name, setName] = useState('Mary');
// 2.
Use an effect for persisting the form
useEffect(function persistForm() {
localStorage.setItem('formData', name);
});
// 3.
Use the surname state variable
const [surname, setSurname] = useState('Poppins');
// 4.
Use an effect for updating the title
useEffect(function updateTitle() {
document.title = name + ' ' + surname;
});
// ...
}
So how does React know which state corresponds to which useState
call? The answer is that React relies on the order in which Hooks are called.
Our example works because the order of the Hook calls is the same on every render:
// ------------
// First render
// ------------
useState('Mary') // 1.
Initialize the name state variable with 'Mary'
useEffect(persistForm) // 2.
Add an effect for persisting the form
useState('Poppins') // 3.
Initialize the surname state variable with 'Poppins'
useEffect(updateTitle) // 4.
Add an effect for updating the title
// -------------
// Second render
// -------------
useState('Mary') // 1.
Read the name state variable (argument is ignored)
useEffect(persistForm) // 2.
Replace the effect for persisting the form
useState('Poppins') // 3.
Read the surname state variable (argument is ignored)
useEffect(updateTitle) // 4.
Replace the effect for updating the title
// ...
As long as the order of the Hook calls is the same between renders, React can associate some local state with each of them.
But what happens if we put a Hook call (for example, the persistForm
effect) inside a condition?
// We're breaking the first rule by using a Hook in a condition
if (name !== '') {
useEffect(function persistForm() {
localStorage.setItem('formData', name);
});
}
The name !== ''
condition is true
on the first render, so we run this Hook.
However, on the next render the user might clear the form, making the condition false
.
Now that we skip this Hook during rendering, the order of the Hook calls becomes different:
useState('Mary') // 1.
Read the name state variable (argument is ignored)
// useEffect(persistForm) // This Hook was skipped!
useState('Poppins') // 2 (but was 3).
Fail to read the surname state variable
useEffect(updateTitle) // 3 (but was 4).
Fail to replace the effect
React wouldn't know what to return for the second useState
Hook call.
React expected that the second Hook call in this component corresponds to the persistForm
effect, just like during the previous render, but it doesn't anymore.
From that point, every next Hook call after the one we skipped would also shift by one, leading to bugs.
This is why Hooks must be called on the top level of our components. If we want to run an effect conditionally, we can put that condition inside our Hook:
useEffect(function persistForm() {
// We're not breaking the first rule anymore
if (name !== '') {
localStorage.setItem('formData', name);
}
});
Note that you don't need to worry about this problem if you use the provided lint rule. But now you also know why Hooks work this way, and which issues the rule is preventing.
Next Steps
Finally, we're ready to learn about writing your own Hooks! Custom Hooks let you combine Hooks provided by React into your own abstractions, and reuse common stateful logic between different components.
Building Your Own Hooks
Hooks are a new addition in React 16.8.
They let you use state and other React features without writing a class.
Building your own Hooks lets you extract component logic into reusable functions.
When we were learning about using the Effect Hook, we saw this component from a chat application that displays a message indicating whether a friend is online or offline:
import React, { useState, useEffect } from 'react';
function FriendStatus(props) {
const [isOnline, setIsOnline] = useState(null); useEffect(() => { function handleStatusChange(status) { setIsOnline(status.isOnline); } ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; });
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
Now let's say that our chat application also has a contact list, and we want to render names of online users with a green color.
We could copy and paste similar logic above into our FriendListItem
component but it wouldn't be ideal:
import React, { useState, useEffect } from 'react';
function FriendListItem(props) {
const [isOnline, setIsOnline] = useState(null); useEffect(() => { function handleStatusChange(status) { setIsOnline(status.isOnline); } ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; });
return (
<li style={{ color: isOnline ? 'green' : 'black' }}>
{props.friend.name}
</li>
);
}
Instead, we'd like to share this logic between FriendStatus
and FriendListItem
.
Traditionally in React, we've had two popular ways to share stateful logic between components: render props and higher-order components.
We will now look at how Hooks solve many of the same problems without forcing you to add more components to the tree.
Extracting a Custom Hook
When we want to share logic between two JavaScript functions, we extract it to a third function.
Both components and Hooks are functions, so this works for them too!
A custom Hook is a JavaScript function whose name starts with ¡±use
¡± and that may call other Hooks. For example, useFriendStatus
below is our first custom Hook:
import { useState, useEffect } from 'react';
function useFriendStatus(friendID) { const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
};
});
return isOnline;
}
There's nothing new inside of it ¡ª the logic is copied from the components above.
Just like in a component, make sure to only call other Hooks unconditionally at the top level of your custom Hook.
Unlike a React component, a custom Hook doesn't need to have a specific signature.
We can decide what it takes as arguments, and what, if anything, it should return.
In other words, it's just like a normal function.
Its name should always start with use
so that you can tell at a glance that the rules of Hooks apply to it.
The purpose of our useFriendStatus
Hook is to subscribe us to a friend's status.
This is why it takes friendID
as an argument, and returns whether this friend is online:
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
// ...
return isOnline;
}
Now let's see how we can use our custom Hook.
Using a Custom Hook
In the beginning, our stated goal was to remove the duplicated logic from the FriendStatus
and FriendListItem
components.
Both of them want to know whether a friend is online.
Now that we've extracted this logic to a useFriendStatus
hook, we can just use it:
function FriendStatus(props) {
const isOnline = useFriendStatus(props.friend.id);
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
function FriendListItem(props) {
const isOnline = useFriendStatus(props.friend.id);
return (
<li style={{ color: isOnline ? 'green' : 'black' }}>
{props.friend.name}
</li>
);
}
Is this code equivalent to the original examples? Yes, it works in exactly the same way.
If you look closely, you'll notice we didn't make any changes to the behavior.
All we did was to extract some common code between two functions into a separate function.
Custom Hooks are a convention that naturally follows from the design of Hooks, rather than a React feature.
Do I have to name my custom Hooks starting with ¡°use
¡±? Please do.
This convention is very important.
Without it, we wouldn't be able to automatically check for violations of rules of Hooks because we couldn't tell if a certain function contains calls to Hooks inside of it.
Do two components using the same Hook share state? No.
Custom Hooks are a mechanism to reuse stateful logic (such as setting up a subscription and remembering the current value), but every time you use a custom Hook, all state and effects inside of it are fully isolated.
How does a custom Hook get isolated state? Each call to a Hook gets isolated state.
Because we call useFriendStatus
directly, from React's point of view our component just calls useState
and useEffect
.
And as we learned earlier, we can call useState
and useEffect
many times in one component, and they will be completely independent.
Tip: Pass Information Between Hooks
Since Hooks are functions, we can pass information between them.
To illustrate this, we'll use another component from our hypothetical chat example.
This is a chat message recipient picker that displays whether the currently selected friend is online:
const friendList = [
{ id: 1, name: 'Phoebe' },
{ id: 2, name: 'Rachel' },
{ id: 3, name: 'Ross' },
];
function ChatRecipientPicker() {
const [recipientID, setRecipientID] = useState(1); const isRecipientOnline = useFriendStatus(recipientID);
return (
<>
<Circle color={isRecipientOnline ? 'green' : 'red'} /> <select
value={recipientID}
onChange={e => setRecipientID(Number(e.target.value))}
>
{friendList.map(friend => (
<option key={friend.id} value={friend.id}>
{friend.name}
</option>
))}
</select>
</>
);
}
We keep the currently chosen friend ID in the recipientID
state variable, and update it if the user chooses a different friend in the <select>
picker.
Because the useState
Hook call gives us the latest value of the recipientID
state variable, we can pass it to our custom useFriendStatus
Hook as an argument:
const [recipientID, setRecipientID] = useState(1);
const isRecipientOnline = useFriendStatus(recipientID);
This lets us know whether the currently selected friend is online.
If we pick a different friend and update the recipientID
state variable, our useFriendStatus
Hook will unsubscribe from the previously selected friend, and subscribe to the status of the newly selected one.
useYourImagination()
Custom Hooks offer the flexibility of sharing logic that wasn't possible in React components before.
You can write custom Hooks that cover a wide range of use cases like form handling, animation, declarative subscriptions, timers, and probably many more we haven't considered.
What's more, you can build Hooks that are just as easy to use as React's built-in features.
Try to resist adding abstraction too early.
Now that function components can do more, it's likely that the average function component in your codebase will become longer.
This is normal ¡ª don't feel like you have to immediately split it into Hooks.
But we also encourage you to start spotting cases where a custom Hook could hide complex logic behind a simple interface, or help untangle a messy component.
For example, maybe you have a complex component that contains a lot of local state that is managed in an ad-hoc way.
useState
doesn't make centralizing the update logic any easier so you might prefer to write it as a Redux reducer:
function todosReducer(state, action) {
switch (action.type) {
case 'add':
return [...state, {
text: action.text,
completed: false
}];
// ...
other actions ...
default:
return state;
}
}
Reducers are very convenient to test in isolation, and scale to express complex update logic.
You can further break them apart into smaller reducers if necessary.
However, you might also enjoy the benefits of using React local state, or might not want to install another library.
So what if we could write a useReducer
Hook that lets us manage the local state of our component with a reducer? A simplified version of it might look like this:
function useReducer(reducer, initialState) {
const [state, setState] = useState(initialState);
function dispatch(action) {
const nextState = reducer(state, action);
setState(nextState);
}
return [state, dispatch];
}
Now we could use it in our component, and let the reducer drive its state management:
function Todos() {
const [todos, dispatch] = useReducer(todosReducer, []);
function handleAddClick(text) {
dispatch({ type: 'add', text });
}
// ...
}
The need to manage local state with a reducer in a complex component is common enough that we've built the useReducer
Hook right into React.
You'll find it together with other built-in Hooks in the Hooks API reference.
Hooks API Reference
Hooks are a new addition in React 16.8.
They let you use state and other React features without writing a class.
This page describes the APIs for the built-in Hooks in React.
If you're new to Hooks, you might want to check out the overview first.
You may also find useful information in the frequently asked questions section.
-
Basic Hooks
useState
useEffect
useContext
-
Additional Hooks
useReducer
useCallback
useMemo
useRef
useImperativeHandle
useLayoutEffect
useDebugValue
Basic Hooks
useState
const [state, setState] = useState(initialState);
Returns a stateful value, and a function to update it.
During the initial render, the returned state (state
) is the same as the value passed as the first argument (initialState
).
The setState
function is used to update the state.
It accepts a new state value and enqueues a re-render of the component.
setState(newState);
During subsequent re-renders, the first value returned by useState
will always be the most recent state after applying updates.
Note
React guarantees that setState
function identity is stable and won't change on re-renders.
This is why it's safe to omit from the useEffect
or useCallback
dependency list.
Functional updates
If the new state is computed using the previous state, you can pass a function to setState
.
The function will receive the previous value, and return an updated value.
Here's an example of a counter component that uses both forms of setState
:
function Counter({initialCount}) {
const [count, setCount] = useState(initialCount);
return (
<>
Count: {count}
<button onClick={() => setCount(initialCount)}>Reset</button>
<button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
<button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
</>
);
}
The ¡±+¡± and ¡±-¡± buttons use the functional form, because the updated value is based on the previous value.
But the ¡°Reset¡± button uses the normal form, because it always sets the count back to the initial value.
If your update function returns the exact same value as the current state, the subsequent rerender will be skipped completely.
Note
Unlike the setState
method found in class components, useState
does not automatically merge update objects.
You can replicate this behavior by combining the function updater form with object spread syntax:
setState(prevState => {
// Object.assign would also work
return {...prevState, ...updatedValues};
});
Another option is useReducer
, which is more suited for managing state objects that contain multiple sub-values.
Lazy initial state
The initialState
argument is the state used during the initial render.
In subsequent renders, it is disregarded.
If the initial state is the result of an expensive computation, you may provide a function instead, which will be executed only on the initial render:
const [state, setState] = useState(() => {
const initialState = someExpensiveComputation(props);
return initialState;
});
Bailing out of a state update
If you update a State Hook to the same value as the current state, React will bail out without rendering the children or firing effects.
(React uses the Object.is
comparison algorithm.)
Note that React may still need to render that specific component again before bailing out.
That shouldn't be a concern because React won't unnecessarily go ¡°deeper¡± into the tree.
If you're doing expensive calculations while rendering, you can optimize them with useMemo
.
useEffect
useEffect(didUpdate);
Accepts a function that contains imperative, possibly effectful code.
Mutations, subscriptions, timers, logging, and other side effects are not allowed inside the main body of a function component (referred to as React's render phase).
Doing so will lead to confusing bugs and inconsistencies in the UI.
Instead, use useEffect
.
The function passed to useEffect
will run after the render is committed to the screen.
Think of effects as an escape hatch from React's purely functional world into the imperative world.
By default, effects run after every completed render, but you can choose to fire them only when certain values have changed.
Cleaning up an effect
Often, effects create resources that need to be cleaned up before the component leaves the screen, such as a subscription or timer ID.
To do this, the function passed to useEffect
may return a clean-up function.
For example, to create a subscription:
useEffect(() => {
const subscription = props.source.subscribe();
return () => {
// Clean up the subscription
subscription.unsubscribe();
};
});
The clean-up function runs before the component is removed from the UI to prevent memory leaks.
Additionally, if a component renders multiple times (as they typically do), the previous effect is cleaned up before executing the next effect.
In our example, this means a new subscription is created on every update.
To avoid firing an effect on every update, refer to the next section.
Timing of effects
Unlike componentDidMount
and componentDidUpdate
, the function passed to useEffect
fires after layout and paint, during a deferred event.
This makes it suitable for the many common side effects, like setting up subscriptions and event handlers, because most types of work shouldn't block the browser from updating the screen.
However, not all effects can be deferred.
For example, a DOM mutation that is visible to the user must fire synchronously before the next paint so that the user does not perceive a visual inconsistency.
(The distinction is conceptually similar to passive versus active event listeners.) For these types of effects, React provides one additional Hook called useLayoutEffect
.
It has the same signature as useEffect
, and only differs in when it is fired.
Although useEffect
is deferred until after the browser has painted, it's guaranteed to fire before any new renders.
React will always flush a previous render's effects before starting a new update.
Conditionally firing an effect
The default behavior for effects is to fire the effect after every completed render.
That way an effect is always recreated if one of its dependencies changes.
However, this may be overkill in some cases, like the subscription example from the previous section.
We don't need to create a new subscription on every update, only if the source
prop has changed.
To implement this, pass a second argument to useEffect
that is the array of values that the effect depends on.
Our updated example now looks like this:
useEffect(
() => {
const subscription = props.source.subscribe();
return () => {
subscription.unsubscribe();
};
},
[props.source],
);
Now the subscription will only be recreated when props.source
changes.
Note
If you use this optimization, make sure the array includes all values from the component scope (such as props and state) that change over time and that are used by the effect.
Otherwise, your code will reference stale values from previous renders.
Learn more about how to deal with functions and what to do when the array values change too often.
If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]
) as a second argument.
This tells React that your effect doesn't depend on any values from props or state, so it never needs to re-run.
This isn't handled as a special case ¡ª it follows directly from how the dependencies array always works.
If you pass an empty array ([]
), the props and state inside the effect will always have their initial values.
While passing []
as the second argument is closer to the familiar componentDidMount
and componentWillUnmount
mental model, there are usually better solutions to avoid re-running effects too often.
Also, don't forget that React defers running useEffect
until after the browser has painted, so doing extra work is less of a problem.
We recommend using the exhaustive-deps
rule as part of our eslint-plugin-react-hooks
package.
It warns when dependencies are specified incorrectly and suggests a fix.
The array of dependencies is not passed as arguments to the effect function.
Conceptually, though, that's what they represent: every value referenced inside the effect function should also appear in the dependencies array.
In the future, a sufficiently advanced compiler could create this array automatically.
useContext
const value = useContext(MyContext);
Accepts a context object (the value returned from React.createContext
) and returns the current context value for that context.
The current context value is determined by the value
prop of the nearest <MyContext.Provider>
above the calling component in the tree.
When the nearest <MyContext.Provider>
above the component updates, this Hook will trigger a rerender with the latest context value
passed to that MyContext
provider.
Even if an ancestor uses React.memo
or shouldComponentUpdate
, a rerender will still happen starting at the component itself using useContext
.
Don't forget that the argument to useContext
must be the context object itself:
-
Correct:
useContext(MyContext)
-
Incorrect:
useContext(MyContext.Consumer)
-
Incorrect:
useContext(MyContext.Provider)
A component calling useContext
will always re-render when the context value changes.
If re-rendering the component is expensive, you can optimize it by using memoization.
Tip
If you're familiar with the context API before Hooks, useContext(MyContext)
is equivalent to static contextType = MyContext
in a class, or to <MyContext.Consumer>
.
useContext(MyContext)
only lets you read the context and subscribe to its changes.
You still need a <MyContext.Provider>
above in the tree to provide the value for this context.
Putting it together with Context.Provider
const themes = {
light: {
foreground: "#000000",
background: "#eeeeee"
},
dark: {
foreground: "#ffffff",
background: "#222222"
}
};
const ThemeContext = React.createContext(themes.light);
function App() {
return (
<ThemeContext.Provider value={themes.dark}>
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
const theme = useContext(ThemeContext); return ( <button style={{ background: theme.background, color: theme.foreground }}> I am styled by theme context! </button> );
}
This example is modified for hooks from a previous example in the Context Advanced Guide, where you can find more information about when and how to use Context.
Additional Hooks
The following Hooks are either variants of the basic ones from the previous section, or only needed for specific edge cases.
Don't stress about learning them up front.
useReducer
const [state, dispatch] = useReducer(reducer, initialArg, init);
An alternative to useState
.
Accepts a reducer of type (state, action) => newState
, and returns the current state paired with a dispatch
method.
(If you're familiar with Redux, you already know how this works.)
useReducer
is usually preferable to useState
when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one.
useReducer
also lets you optimize performance for components that trigger deep updates because you can pass dispatch
down instead of callbacks.
Here's the counter example from the useState
section, rewritten to use a reducer:
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
Note
React guarantees that dispatch
function identity is stable and won't change on re-renders.
This is why it's safe to omit from the useEffect
or useCallback
dependency list.
Specifying the initial state
There are two different ways to initialize useReducer
state.
You may choose either one depending on the use case.
The simplest way is to pass the initial state as a second argument:
const [state, dispatch] = useReducer(
reducer,
{count: initialCount} );
Note
React doesn't use the state = initialState
argument convention popularized by Redux.
The initial value sometimes needs to depend on props and so is specified from the Hook call instead.
If you feel strongly about this, you can call useReducer(reducer, undefined, reducer)
to emulate the Redux behavior, but it's not encouraged.
Lazy initialization
You can also create the initial state lazily.
To do this, you can pass an init
function as the third argument.
The initial state will be set to init(initialArg)
.
It lets you extract the logic for calculating the initial state outside the reducer.
This is also handy for resetting the state later in response to an action:
function init(initialCount) { return {count: initialCount};}
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
case 'reset': return init(action.payload); default:
throw new Error();
}
}
function Counter({initialCount}) {
const [state, dispatch] = useReducer(reducer, initialCount, init); return (
<>
Count: {state.count}
<button
onClick={() => dispatch({type: 'reset', payload: initialCount})}> Reset
</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
Bailing out of a dispatch
If you return the same value from a Reducer Hook as the current state, React will bail out without rendering the children or firing effects.
(React uses the Object.is
comparison algorithm.)
Note that React may still need to render that specific component again before bailing out.
That shouldn't be a concern because React won't unnecessarily go ¡°deeper¡± into the tree.
If you're doing expensive calculations while rendering, you can optimize them with useMemo
.
useCallback
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
Returns a memoized callback.
Pass an inline callback and an array of dependencies.
useCallback
will return a memoized version of the callback that only changes if one of the dependencies has changed.
This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders (e.g.
shouldComponentUpdate
).
useCallback(fn, deps)
is equivalent to useMemo(() => fn, deps)
.
Note
The array of dependencies is not passed as arguments to the callback.
Conceptually, though, that's what they represent: every value referenced inside the callback should also appear in the dependencies array.
In the future, a sufficiently advanced compiler could create this array automatically.
We recommend using the exhaustive-deps
rule as part of our eslint-plugin-react-hooks
package.
It warns when dependencies are specified incorrectly and suggests a fix.
useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
Returns a memoized value.
Pass a ¡°create¡± function and an array of dependencies.
useMemo
will only recompute the memoized value when one of the dependencies has changed.
This optimization helps to avoid expensive calculations on every render.
Remember that the function passed to useMemo
runs during rendering.
Don't do anything there that you wouldn't normally do while rendering.
For example, side effects belong in useEffect
, not useMemo
.
If no array is provided, a new value will be computed on every render.
You may rely on useMemo
as a performance optimization, not as a semantic guarantee. In the future, React may choose to ¡°forget¡± some previously memoized values and recalculate them on next render, e.g.
to free memory for offscreen components.
Write your code so that it still works without useMemo
¡ª and then add it to optimize performance.
Note
The array of dependencies is not passed as arguments to the function.
Conceptually, though, that's what they represent: every value referenced inside the function should also appear in the dependencies array.
In the future, a sufficiently advanced compiler could create this array automatically.
We recommend using the exhaustive-deps
rule as part of our eslint-plugin-react-hooks
package.
It warns when dependencies are specified incorrectly and suggests a fix.
useRef
const refContainer = useRef(initialValue);
useRef
returns a mutable ref object whose .current
property is initialized to the passed argument (initialValue
).
The returned object will persist for the full lifetime of the component.
A common use case is to access a child imperatively:
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` points to the mounted text input element
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
Essentially, useRef
is like a ¡°box¡± that can hold a mutable value in its .current
property.
You might be familiar with refs primarily as a way to access the DOM.
If you pass a ref object to React with <div ref={myRef} />
, React will set its .current
property to the corresponding DOM node whenever that node changes.
However, useRef()
is useful for more than the ref
attribute.
It's handy for keeping any mutable value around similar to how you'd use instance fields in classes.
This works because useRef()
creates a plain JavaScript object.
The only difference between useRef()
and creating a {current: ...}
object yourself is that useRef
will give you the same ref object on every render.
Keep in mind that useRef
doesn't notify you when its content changes.
Mutating the .current
property doesn't cause a re-render.
If you want to run some code when React attaches or detaches a ref to a DOM node, you may want to use a callback ref instead.
useImperativeHandle
useImperativeHandle(ref, createHandle, [deps])
useImperativeHandle
customizes the instance value that is exposed to parent components when using ref
.
As always, imperative code using refs should be avoided in most cases.
useImperativeHandle
should be used with forwardRef
:
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ...
/>;
}
FancyInput = forwardRef(FancyInput);
In this example, a parent component that renders <FancyInput ref={inputRef} />
would be able to call inputRef.current.focus()
.
useLayoutEffect
The signature is identical to useEffect
, but it fires synchronously after all DOM mutations.
Use this to read layout from the DOM and synchronously re-render.
Updates scheduled inside useLayoutEffect
will be flushed synchronously, before the browser has a chance to paint.
Prefer the standard useEffect
when possible to avoid blocking visual updates.
Tip
If you're migrating code from a class component, note useLayoutEffect
fires in the same phase as componentDidMount
and componentDidUpdate
.
However, we recommend starting with useEffect
first and only trying useLayoutEffect
if that causes a problem.
If you use server rendering, keep in mind that neither useLayoutEffect
nor useEffect
can run until the JavaScript is downloaded.
This is why React warns when a server-rendered component contains useLayoutEffect
.
To fix this, either move that logic to useEffect
(if it isn't necessary for the first render), or delay showing that component until after the client renders (if the HTML looks broken until useLayoutEffect
runs).
To exclude a component that needs layout effects from the server-rendered HTML, render it conditionally with showChild && <Child />
and defer showing it with useEffect(() => { setShowChild(true); }, [])
.
This way, the UI doesn't appear broken before hydration.
useDebugValue
useDebugValue(value)
useDebugValue
can be used to display a label for custom hooks in React DevTools.
For example, consider the useFriendStatus
custom Hook described in ¡°Building Your Own Hooks¡±:
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
// ...
// Show a label in DevTools next to this Hook // e.g.
"FriendStatus: Online" useDebugValue(isOnline ? 'Online' : 'Offline');
return isOnline;
}
Tip
We don't recommend adding debug values to every custom Hook.
It's most valuable for custom Hooks that are part of shared libraries.
Defer formatting debug values
In some cases formatting a value for display might be an expensive operation.
It's also unnecessary unless a Hook is actually inspected.
For this reason useDebugValue
accepts a formatting function as an optional second parameter.
This function is only called if the Hooks are inspected.
It receives the debug value as a parameter and should return a formatted display value.
For example a custom Hook that returned a Date
value could avoid calling the toDateString
function unnecessarily by passing the following formatter:
useDebugValue(date, date => date.toDateString());
Hooks FAQ
Hooks are a new addition in React 16.8.
They let you use state and other React features without writing a class.
This page answers some of the frequently asked questions about Hooks.
-
Adoption Strategy
- Which versions of React include Hooks?
- Do I need to rewrite all my class components?
- What can I do with Hooks that I couldn't with classes?
- How much of my React knowledge stays relevant?
- Should I use Hooks, classes, or a mix of both?
- Do Hooks cover all use cases for classes?
- Do Hooks replace render props and higher-order components?
- What do Hooks mean for popular APIs like Redux connect() and React Router?
- Do Hooks work with static typing?
- How to test components that use Hooks?
- What exactly do the lint rules enforce?
-
From Classes to Hooks
- How do lifecycle methods correspond to Hooks?
- How can I do data fetching with Hooks?
- Is there something like instance variables?
- Should I use one or many state variables?
- Can I run an effect only on updates?
- How to get the previous props or state?
- Why am I seeing stale props or state inside my function?
- How do I implement getDerivedStateFromProps?
- Is there something like forceUpdate?
- Can I make a ref to a function component?
- How can I measure a DOM node?
- What does const [thing, setThing] = useState() mean?
-
Performance Optimizations
- Can I skip an effect on updates?
- Is it safe to omit functions from the list of dependencies?
- What can I do if my effect dependencies change too often?
- How do I implement shouldComponentUpdate?
- How to memoize calculations?
- How to create expensive objects lazily?
- Are Hooks slow because of creating functions in render?
- How to avoid passing callbacks down?
- How to read an often-changing value from useCallback?
-
Under the Hood
- How does React associate Hook calls with components?
- What is the prior art for Hooks?
Adoption Strategy
Which versions of React include Hooks?
Starting with 16.8.0, React includes a stable implementation of React Hooks for:
- React DOM
- React Native
- React DOM Server
- React Test Renderer
- React Shallow Renderer
Note that to enable Hooks, all React packages need to be 16.8.0 or higher.
Hooks won't work if you forget to update, for example, React DOM.
React Native 0.59 and above support Hooks.
Do I need to rewrite all my class components?
No.
There are no plans to remove classes from React ¡ª we all need to keep shipping products and can't afford rewrites.
We recommend trying Hooks in new code.
What can I do with Hooks that I couldn't with classes?
Hooks offer a powerful and expressive new way to reuse functionality between components.
¡°Building Your Own Hooks¡± provides a glimpse of what's possible.
This article by a React core team member dives deeper into the new capabilities unlocked by Hooks.
How much of my React knowledge stays relevant?
Hooks are a more direct way to use the React features you already know ¡ª such as state, lifecycle, context, and refs.
They don't fundamentally change how React works, and your knowledge of components, props, and top-down data flow is just as relevant.
Hooks do have a learning curve of their own.
If there's something missing in this documentation, raise an issue and we'll try to help.
Should I use Hooks, classes, or a mix of both?
When you're ready, we'd encourage you to start trying Hooks in new components you write.
Make sure everyone on your team is on board with using them and familiar with this documentation.
We don't recommend rewriting your existing classes to Hooks unless you planned to rewrite them anyway (e.g.
to fix bugs).
You can't use Hooks inside a class component, but you can definitely mix classes and function components with Hooks in a single tree.
Whether a component is a class or a function that uses Hooks is an implementation detail of that component.
In the longer term, we expect Hooks to be the primary way people write React components.
Do Hooks cover all use cases for classes?
Our goal is for Hooks to cover all use cases for classes as soon as possible.
There are no Hook equivalents to the uncommon getSnapshotBeforeUpdate
, getDerivedStateFromError
and componentDidCatch
lifecycles yet, but we plan to add them soon.
It is an early time for Hooks, and some third-party libraries might not be compatible with Hooks at the moment.
Do Hooks replace render props and higher-order components?
Often, render props and higher-order components render only a single child.
We think Hooks are a simpler way to serve this use case.
There is still a place for both patterns (for example, a virtual scroller component might have a renderItem
prop, or a visual container component might have its own DOM structure).
But in most cases, Hooks will be sufficient and can help reduce nesting in your tree.
What do Hooks mean for popular APIs like Redux connect()
and React Router?
You can continue to use the exact same APIs as you always have; they'll continue to work.
React Redux since v7.1.0 supports Hooks API and exposes hooks like useDispatch
or useSelector
.
React Router supports hooks since v5.1.
Other libraries might support hooks in the future too.
Do Hooks work with static typing?
Hooks were designed with static typing in mind.
Because they're functions, they are easier to type correctly than patterns like higher-order components.
The latest Flow and TypeScript React definitions include support for React Hooks.
Importantly, custom Hooks give you the power to constrain React API if you'd like to type them more strictly in some way.
React gives you the primitives, but you can combine them in different ways than what we provide out of the box.
How to test components that use Hooks?
From React's point of view, a component using Hooks is just a regular component.
If your testing solution doesn't rely on React internals, testing components with Hooks shouldn't be different from how you normally test components.
Note
Testing Recipes include many examples that you can copy and paste.
For example, let's say we have this counter component:
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
We'll test it using React DOM.
To make sure that the behavior matches what happens in the browser, we'll wrap the code rendering and updating it into ReactTestUtils.act()
calls:
import React from 'react';
import ReactDOM from 'react-dom';
import { act } from 'react-dom/test-utils';import Counter from './Counter';
let container;
beforeEach(() => {
container = document.createElement('div');
document.body.appendChild(container);
});
afterEach(() => {
document.body.removeChild(container);
container = null;
});
it('can render and update a counter', () => {
// Test first render and effect
act(() => { ReactDOM.render(<Counter />, container); }); const button = container.querySelector('button');
const label = container.querySelector('p');
expect(label.textContent).toBe('You clicked 0 times');
expect(document.title).toBe('You clicked 0 times');
// Test second render and effect
act(() => { button.dispatchEvent(new MouseEvent('click', {bubbles: true})); }); expect(label.textContent).toBe('You clicked 1 times');
expect(document.title).toBe('You clicked 1 times');
});
The calls to act()
will also flush the effects inside of them.
If you need to test a custom Hook, you can do so by creating a component in your test, and using your Hook from it.
Then you can test the component you wrote.
To reduce the boilerplate, we recommend using React Testing Library which is designed to encourage writing tests that use your components as the end users do.
For more information, check out Testing Recipes.
What exactly do the lint rules enforce?
We provide an ESLint plugin that enforces rules of Hooks to avoid bugs.
It assumes that any function starting with ¡±use
¡± and a capital letter right after it is a Hook.
We recognize this heuristic isn't perfect and there may be some false positives, but without an ecosystem-wide convention there is just no way to make Hooks work well ¡ª and longer names will discourage people from either adopting Hooks or following the convention.
In particular, the rule enforces that:
- Calls to Hooks are either inside a
PascalCase
function (assumed to be a component) or another useSomething
function (assumed to be a custom Hook).
- Hooks are called in the same order on every render.
There are a few more heuristics, and they might change over time as we fine-tune the rule to balance finding bugs with avoiding false positives.
From Classes to Hooks
How do lifecycle methods correspond to Hooks?
-
constructor
: Function components don't need a constructor.
You can initialize the state in the useState
call.
If computing the initial state is expensive, you can pass a function to useState
.
-
getDerivedStateFromProps
: Schedule an update while rendering instead.
-
shouldComponentUpdate
: See React.memo
below.
-
render
: This is the function component body itself.
-
componentDidMount
, componentDidUpdate
, componentWillUnmount
: The useEffect
Hook can express all combinations of these (including less common cases).
-
getSnapshotBeforeUpdate
, componentDidCatch
and getDerivedStateFromError
: There are no Hook equivalents for these methods yet, but they will be added soon.
How can I do data fetching with Hooks?
Here is a small demo to get you started.
To learn more, check out this article about data fetching with Hooks.
Is there something like instance variables?
Yes! The useRef()
Hook isn't just for DOM refs.
The ¡°ref¡± object is a generic container whose current
property is mutable and can hold any value, similar to an instance property on a class.
You can write to it from inside useEffect
:
function Timer() {
const intervalRef = useRef();
useEffect(() => {
const id = setInterval(() => {
// ...
});
intervalRef.current = id; return () => {
clearInterval(intervalRef.current);
};
});
// ...
}
If we just wanted to set an interval, we wouldn't need the ref (id
could be local to the effect), but it's useful if we want to clear the interval from an event handler:
// ...
function handleCancelClick() {
clearInterval(intervalRef.current); }
// ...
Conceptually, you can think of refs as similar to instance variables in a class.
Unless you're doing lazy initialization, avoid setting refs during rendering ¡ª this can lead to surprising behavior.
Instead, typically you want to modify refs in event handlers and effects.
Should I use one or many state variables?
If you're coming from classes, you might be tempted to always call useState()
once and put all state into a single object.
You can do it if you'd like.
Here is an example of a component that follows the mouse movement.
We keep its position and size in the local state:
function Box() {
const [state, setState] = useState({ left: 0, top: 0, width: 100, height: 100 });
// ...
}
Now let's say we want to write some logic that changes left
and top
when the user moves their mouse.
Note how we have to merge these fields into the previous state object manually:
// ...
useEffect(() => {
function handleWindowMouseMove(e) {
// Spreading "...state" ensures we don't "lose" width and height setState(state => ({ ...state, left: e.pageX, top: e.pageY })); }
// Note: this implementation is a bit simplified
window.addEventListener('mousemove', handleWindowMouseMove);
return () => window.removeEventListener('mousemove', handleWindowMouseMove);
}, []);
// ...
This is because when we update a state variable, we replace its value.
This is different from this.setState
in a class, which merges the updated fields into the object.
If you miss automatic merging, you could write a custom useLegacyState
Hook that merges object state updates.
However, we recommend to split state into multiple state variables based on which values tend to change together.
For example, we could split our component state into position
and size
objects, and always replace the position
with no need for merging:
function Box() {
const [position, setPosition] = useState({ left: 0, top: 0 }); const [size, setSize] = useState({ width: 100, height: 100 });
useEffect(() => {
function handleWindowMouseMove(e) {
setPosition({ left: e.pageX, top: e.pageY }); }
// ...
Separating independent state variables also has another benefit.
It makes it easy to later extract some related logic into a custom Hook, for example:
function Box() {
const position = useWindowPosition(); const [size, setSize] = useState({ width: 100, height: 100 });
// ...
}
function useWindowPosition() { const [position, setPosition] = useState({ left: 0, top: 0 });
useEffect(() => {
// ...
}, []);
return position;
}
Note how we were able to move the useState
call for the position
state variable and the related effect into a custom Hook without changing their code.
If all state was in a single object, extracting it would be more difficult.
Both putting all state in a single useState
call, and having a useState
call per each field can work.
Components tend to be most readable when you find a balance between these two extremes, and group related state into a few independent state variables.
If the state logic becomes complex, we recommend managing it with a reducer or a custom Hook.
Can I run an effect only on updates?
This is a rare use case.
If you need it, you can use a mutable ref to manually store a boolean value corresponding to whether you are on the first or a subsequent render, then check that flag in your effect.
(If you find yourself doing this often, you could create a custom Hook for it.)
How to get the previous props or state?
Currently, you can do it manually with a ref:
function Counter() {
const [count, setCount] = useState(0);
const prevCountRef = useRef();
useEffect(() => {
prevCountRef.current = count; });
const prevCount = prevCountRef.current;
return <h2>Now: {count}, before: {prevCount}</h2>;
}
This might be a bit convoluted but you can extract it into a custom Hook:
function Counter() {
const [count, setCount] = useState(0);
const prevCount = usePrevious(count); return <h2>Now: {count}, before: {prevCount}</h2>;
}
function usePrevious(value) { const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
Note how this would work for props, state, or any other calculated value.
function Counter() {
const [count, setCount] = useState(0);
const calculation = count + 100;
const prevCalculation = usePrevious(calculation); // ...
It's possible that in the future React will provide a usePrevious
Hook out of the box since it's a relatively common use case.
See also the recommended pattern for derived state.
Why am I seeing stale props or state inside my function?
Any function inside a component, including event handlers and effects, ¡°sees¡± the props and state from the render it was created in.
For example, consider code like this:
function Example() {
const [count, setCount] = useState(0);
function handleAlertClick() {
setTimeout(() => {
alert('You clicked on: ' + count);
}, 3000);
}
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
<button onClick={handleAlertClick}>
Show alert
</button>
</div>
);
}
If you first click ¡°Show alert¡± and then increment the counter, the alert will show the count
variable at the time you clicked the ¡°Show alert¡± button.
This prevents bugs caused by the code assuming props and state don't change.
If you intentionally want to read the latest state from some asynchronous callback, you could keep it in a ref, mutate it, and read from it.
Finally, another possible reason you're seeing stale props or state is if you use the ¡°dependency array¡± optimization but didn't correctly specify all the dependencies.
For example, if an effect specifies []
as the second argument but reads someProp
inside, it will keep ¡°seeing¡± the initial value of someProp
.
The solution is to either remove the dependency array, or to fix it.
Here's how you can deal with functions, and here's other common strategies to run effects less often without incorrectly skipping dependencies.
Note
We provide an exhaustive-deps
ESLint rule as a part of the eslint-plugin-react-hooks
package.
It warns when dependencies are specified incorrectly and suggests a fix.
How do I implement getDerivedStateFromProps
?
While you probably don't need it, in rare cases that you do (such as implementing a <Transition>
component), you can update the state right during rendering.
React will re-run the component with updated state immediately after exiting the first render so it wouldn't be expensive.
Here, we store the previous value of the row
prop in a state variable so that we can compare:
function ScrollView({row}) {
const [isScrollingDown, setIsScrollingDown] = useState(false);
const [prevRow, setPrevRow] = useState(null);
if (row !== prevRow) {
// Row changed since last render.
Update isScrollingDown.
setIsScrollingDown(prevRow !== null && row > prevRow);
setPrevRow(row);
}
return `Scrolling down: ${isScrollingDown}`;
}
This might look strange at first, but an update during rendering is exactly what getDerivedStateFromProps
has always been like conceptually.
Is there something like forceUpdate?
Both useState
and useReducer
Hooks bail out of updates if the next value is the same as the previous one.
Mutating state in place and calling setState
will not cause a re-render.
Normally, you shouldn't mutate local state in React.
However, as an escape hatch, you can use an incrementing counter to force a re-render even if the state has not changed:
const [ignored, forceUpdate] = useReducer(x => x + 1, 0);
function handleClick() {
forceUpdate();
}
Try to avoid this pattern if possible.
Can I make a ref to a function component?
While you shouldn't need this often, you may expose some imperative methods to a parent component with the useImperativeHandle
Hook.
How can I measure a DOM node?
One rudimentary way to measure the position or size of a DOM node is to use a callback ref.
React will call that callback whenever the ref gets attached to a different node.
Here is a small demo:
function MeasureExample() {
const [height, setHeight] = useState(0);
const measuredRef = useCallback(node => { if (node !== null) { setHeight(node.getBoundingClientRect().height); } }, []);
return (
<>
<h2 ref={measuredRef}>Hello, world</h2> <h3>The above header is {Math.round(height)}px tall</h3>
</>
);
}
We didn't choose useRef
in this example because an object ref doesn't notify us about changes to the current ref value.
Using a callback ref ensures that even if a child component displays the measured node later (e.g.
in response to a click), we still get notified about it in the parent component and can update the measurements.
Note that we pass []
as a dependency array to useCallback
.
This ensures that our ref callback doesn't change between the re-renders, and so React won't call it unnecessarily.
In this example, the callback ref will be called only when the component mounts and unmounts, since the rendered <h2>
component stays present throughout any rerenders.
If you want to be notified any time a component resizes, you may want to use ResizeObserver
or a third-party Hook built on it.
If you want, you can extract this logic into a reusable Hook:
function MeasureExample() {
const [rect, ref] = useClientRect(); return (
<>
<h2 ref={ref}>Hello, world</h2>
{rect !== null &&
<h3>The above header is {Math.round(rect.height)}px tall</h3>
}
</>
);
}
function useClientRect() {
const [rect, setRect] = useState(null);
const ref = useCallback(node => {
if (node !== null) {
setRect(node.getBoundingClientRect());
}
}, []);
return [rect, ref];
}
What does const [thing, setThing] = useState()
mean?
If you're not familiar with this syntax, check out the explanation in the State Hook documentation.
Performance Optimizations
Can I skip an effect on updates?
Yes.
See conditionally firing an effect.
Note that forgetting to handle updates often introduces bugs, which is why this isn't the default behavior.
Is it safe to omit functions from the list of dependencies?
Generally speaking, no.
function Example({ someProp }) {
function doSomething() {
console.log(someProp); }
useEffect(() => {
doSomething();
}, []); // This is not safe (it calls `doSomething` which uses `someProp`)}
It's difficult to remember which props or state are used by functions outside of the effect.
This is why usually you'll want to declare functions needed by an effect inside of it. Then it's easy to see what values from the component scope that effect depends on:
function Example({ someProp }) {
useEffect(() => {
function doSomething() {
console.log(someProp); }
doSomething();
}, [someProp]); // OK (our effect only uses `someProp`)}
If after that we still don't use any values from the component scope, it's safe to specify []
:
useEffect(() => {
function doSomething() {
console.log('hello');
}
doSomething();
}, []); // OK in this example because we don't use *any* values from component scope
Depending on your use case, there are a few more options described below.
Note
We provide the exhaustive-deps
ESLint rule as a part of the eslint-plugin-react-hooks
package.
It helps you find components that don't handle updates consistently.
Let's see why this matters.
If you specify a list of dependencies as the last argument to useEffect
, useLayoutEffect
, useMemo
, useCallback
, or useImperativeHandle
, it must include all values that are used inside the callback and participate in the React data flow.
That includes props, state, and anything derived from them.
It is only safe to omit a function from the dependency list if nothing in it (or the functions called by it) references props, state, or values derived from them.
This example has a bug:
function ProductPage({ productId }) {
const [product, setProduct] = useState(null);
async function fetchProduct() {
const response = await fetch('http://myapi/product/' + productId); // Uses productId prop const json = await response.json();
setProduct(json);
}
useEffect(() => {
fetchProduct();
}, []); // Invalid because `fetchProduct` uses `productId` // ...
}
The recommended fix is to move that function inside of your effect.
That makes it easy to see which props or state your effect uses, and to ensure they're all declared:
function ProductPage({ productId }) {
const [product, setProduct] = useState(null);
useEffect(() => {
// By moving this function inside the effect, we can clearly see the values it uses.
async function fetchProduct() { const response = await fetch('http://myapi/product/' + productId); const json = await response.json(); setProduct(json); }
fetchProduct();
}, [productId]); // Valid because our effect only uses productId // ...
}
This also allows you to handle out-of-order responses with a local variable inside the effect:
useEffect(() => {
let ignore = false; async function fetchProduct() {
const response = await fetch('http://myapi/product/' + productId);
const json = await response.json();
if (!ignore) setProduct(json); }
fetchProduct();
return () => { ignore = true }; }, [productId]);
We moved the function inside the effect so it doesn't need to be in its dependency list.
Tip
Check out this small demo and this article to learn more about data fetching with Hooks.
If for some reason you can't move a function inside an effect, there are a few more options:
-
You can try moving that function outside of your component.
In that case, the function is guaranteed to not reference any props or state, and also doesn't need to be in the list of dependencies.
- If the function you're calling is a pure computation and is safe to call while rendering, you may call it outside of the effect instead, and make the effect depend on the returned value.
- As a last resort, you can add a function to effect dependencies but wrap its definition into the
useCallback
Hook.
This ensures it doesn't change on every render unless its own dependencies also change:
function ProductPage({ productId }) {
// Wrap with useCallback to avoid change on every render const fetchProduct = useCallback(() => { // ...
Does something with productId ...
}, [productId]); // All useCallback dependencies are specified
return <ProductDetails fetchProduct={fetchProduct} />;
}
function ProductDetails({ fetchProduct }) {
useEffect(() => {
fetchProduct();
}, [fetchProduct]); // All useEffect dependencies are specified
// ...
}
Note that in the above example we need to keep the function in the dependencies list.
This ensures that a change in the productId
prop of ProductPage
automatically triggers a refetch in the ProductDetails
component.
What can I do if my effect dependencies change too often?
Sometimes, your effect may be using state that changes too often.
You might be tempted to omit that state from a list of dependencies, but that usually leads to bugs:
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => {
setCount(count + 1); // This effect depends on the `count` state }, 1000);
return () => clearInterval(id);
}, []); // Bug: `count` is not specified as a dependency
return <h2>{count}</h2>;
}
The empty set of dependencies, []
, means that the effect will only run once when the component mounts, and not on every re-render.
The problem is that inside the setInterval
callback, the value of count
does not change, because we've created a closure with the value of count
set to 0
as it was when the effect callback ran.
Every second, this callback then calls setCount(0 + 1)
, so the count never goes above 1.
Specifying [count]
as a list of dependencies would fix the bug, but would cause the interval to be reset on every change.
Effectively, each setInterval
would get one chance to execute before being cleared (similar to a setTimeout
.) That may not be desirable.
To fix this, we can use the functional update form of setState
.
It lets us specify how the state needs to change without referencing the current state:
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => {
setCount(c => c + 1); // This doesn't depend on `count` variable outside }, 1000);
return () => clearInterval(id);
}, []); // Our effect doesn't use any variables in the component scope
return <h2>{count}</h2>;
}
(The identity of the setCount
function is guaranteed to be stable so it's safe to omit.)
Now, the setInterval
callback executes once a second, but each time the inner call to setCount
can use an up-to-date value for count
(called c
in the callback here.)
In more complex cases (such as if one state depends on another state), try moving the state update logic outside the effect with the useReducer
Hook.
This article offers an example of how you can do this.
The identity of the dispatch
function from useReducer
is always stable ¡ª even if the reducer function is declared inside the component and reads its props.
As a last resort, if you want something like this
in a class, you can use a ref to hold a mutable variable.
Then you can write and read to it.
For example:
function Example(props) {
// Keep latest props in a ref.
const latestProps = useRef(props); useEffect(() => { latestProps.current = props; });
useEffect(() => {
function tick() {
// Read latest props at any time console.log(latestProps.current); }
const id = setInterval(tick, 1000);
return () => clearInterval(id);
}, []); // This effect never re-runs}
Only do this if you couldn't find a better alternative, as relying on mutation makes components less predictable.
If there's a specific pattern that doesn't translate well, file an issue with a runnable example code and we can try to help.
How do I implement shouldComponentUpdate
?
You can wrap a function component with React.memo
to shallowly compare its props:
const Button = React.memo((props) => {
// your component
});
It's not a Hook because it doesn't compose like Hooks do.
React.memo
is equivalent to PureComponent
, but it only compares props.
(You can also add a second argument to specify a custom comparison function that takes the old and new props.
If it returns true, the update is skipped.)
React.memo
doesn't compare state because there is no single state object to compare.
But you can make children pure too, or even optimize individual children with useMemo
.
How to memoize calculations?
The useMemo
Hook lets you cache calculations between multiple renders by ¡°remembering¡± the previous computation:
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
This code calls computeExpensiveValue(a, b)
.
But if the dependencies [a, b]
haven't changed since the last value, useMemo
skips calling it a second time and simply reuses the last value it returned.
Remember that the function passed to useMemo
runs during rendering.
Don't do anything there that you wouldn't normally do while rendering.
For example, side effects belong in useEffect
, not useMemo
.
You may rely on useMemo
as a performance optimization, not as a semantic guarantee. In the future, React may choose to ¡°forget¡± some previously memoized values and recalculate them on next render, e.g.
to free memory for offscreen components.
Write your code so that it still works without useMemo
¡ª and then add it to optimize performance.
(For rare cases when a value must never be recomputed, you can lazily initialize a ref.)
Conveniently, useMemo
also lets you skip an expensive re-render of a child:
function Parent({ a, b }) {
// Only re-rendered if `a` changes:
const child1 = useMemo(() => <Child1 a={a} />, [a]);
// Only re-rendered if `b` changes:
const child2 = useMemo(() => <Child2 b={b} />, [b]);
return (
<>
{child1}
{child2}
</>
)
}
Note that this approach won't work in a loop because Hook calls can't be placed inside loops.
But you can extract a separate component for the list item, and call useMemo
there.
How to create expensive objects lazily?
useMemo
lets you memoize an expensive calculation if the dependencies are the same.
However, it only serves as a hint, and doesn't guarantee the computation won't re-run.
But sometimes you need to be sure an object is only created once.
The first common use case is when creating the initial state is expensive:
function Table(props) {
// createRows() is called on every render
const [rows, setRows] = useState(createRows(props.count));
// ...
}
To avoid re-creating the ignored initial state, we can pass a function to useState
:
function Table(props) {
// createRows() is only called once
const [rows, setRows] = useState(() => createRows(props.count));
// ...
}
React will only call this function during the first render.
See the useState
API reference.
You might also occasionally want to avoid re-creating the useRef()
initial value. For example, maybe you want to ensure some imperative class instance only gets created once:
function Image(props) {
// IntersectionObserver is created on every render
const ref = useRef(new IntersectionObserver(onIntersect));
// ...
}
useRef
does not accept a special function overload like useState
.
Instead, you can write your own function that creates and sets it lazily:
function Image(props) {
const ref = useRef(null);
// IntersectionObserver is created lazily once
function getObserver() {
if (ref.current === null) {
ref.current = new IntersectionObserver(onIntersect);
}
return ref.current;
}
// When you need it, call getObserver()
// ...
}
This avoids creating an expensive object until it's truly needed for the first time.
If you use Flow or TypeScript, you can also give getObserver()
a non-nullable type for convenience.
Are Hooks slow because of creating functions in render?
No.
In modern browsers, the raw performance of closures compared to classes doesn't differ significantly except in extreme scenarios.
In addition, consider that the design of Hooks is more efficient in a couple ways:
- Hooks avoid a lot of the overhead that classes require, like the cost of creating class instances and binding event handlers in the constructor.
-
Idiomatic code using Hooks doesn't need the deep component tree nesting that is prevalent in codebases that use higher-order components, render props, and context.
With smaller component trees, React has less work to do.
Traditionally, performance concerns around inline functions in React have been related to how passing new callbacks on each render breaks shouldComponentUpdate
optimizations in child components.
Hooks approach this problem from three sides.
-
The
useCallback
Hook lets you keep the same callback reference between re-renders so that shouldComponentUpdate
continues to work:
// Will not change unless `a` or `b` changes
const memoizedCallback = useCallback(() => { doSomething(a, b);
}, [a, b]);
- The
useMemo
Hook makes it easier to control when individual children update, reducing the need for pure components.
- Finally, the
useReducer
Hook reduces the need to pass callbacks deeply, as explained below.
How to avoid passing callbacks down?
We've found that most people don't enjoy manually passing callbacks through every level of a component tree.
Even though it is more explicit, it can feel like a lot of ¡°plumbing¡±.
In large component trees, an alternative we recommend is to pass down a dispatch
function from useReducer
via context:
const TodosDispatch = React.createContext(null);
function TodosApp() {
// Note: `dispatch` won't change between re-renders const [todos, dispatch] = useReducer(todosReducer);
return (
<TodosDispatch.Provider value={dispatch}>
<DeepTree todos={todos} />
</TodosDispatch.Provider>
);
}
Any child in the tree inside TodosApp
can use the dispatch
function to pass actions up to TodosApp
:
function DeepChild(props) {
// If we want to perform an action, we can get dispatch from context.
const dispatch = useContext(TodosDispatch);
function handleClick() {
dispatch({ type: 'add', text: 'hello' });
}
return (
<button onClick={handleClick}>Add todo</button>
);
}
This is both more convenient from the maintenance perspective (no need to keep forwarding callbacks), and avoids the callback problem altogether.
Passing dispatch
down like this is the recommended pattern for deep updates.
Note that you can still choose whether to pass the application state down as props (more explicit) or as context (more convenient for very deep updates).
If you use context to pass down the state too, use two different context types ¡ª the dispatch
context never changes, so components that read it don't need to rerender unless they also need the application state.
How to read an often-changing value from useCallback
?
Note
We recommend to pass dispatch
down in context rather than individual callbacks in props.
The approach below is only mentioned here for completeness and as an escape hatch.
Also note that this pattern might cause problems in the concurrent mode.
We plan to provide more ergonomic alternatives in the future, but the safest solution right now is to always invalidate the callback if some value it depends on changes.
In some rare cases you might need to memoize a callback with useCallback
but the memoization doesn't work very well because the inner function has to be re-created too often.
If the function you're memoizing is an event handler and isn't used during rendering, you can use ref as an instance variable, and save the last committed value into it manually:
function Form() {
const [text, updateText] = useState('');
const textRef = useRef();
useEffect(() => {
textRef.current = text; // Write it to the ref });
const handleSubmit = useCallback(() => {
const currentText = textRef.current; // Read it from the ref alert(currentText);
}, [textRef]); // Don't recreate handleSubmit like [text] would do
return (
<>
<input value={text} onChange={e => updateText(e.target.value)} />
<ExpensiveTree onSubmit={handleSubmit} />
</>
);
}
This is a rather convoluted pattern but it shows that you can do this escape hatch optimization if you need it.
It's more bearable if you extract it to a custom Hook:
function Form() {
const [text, updateText] = useState('');
// Will be memoized even if `text` changes:
const handleSubmit = useEventCallback(() => { alert(text);
}, [text]);
return (
<>
<input value={text} onChange={e => updateText(e.target.value)} />
<ExpensiveTree onSubmit={handleSubmit} />
</>
);
}
function useEventCallback(fn, dependencies) { const ref = useRef(() => {
throw new Error('Cannot call an event handler while rendering.');
});
useEffect(() => {
ref.current = fn;
}, [fn, ...dependencies]);
return useCallback(() => {
const fn = ref.current;
return fn();
}, [ref]);
}
In either case, we don't recommend this pattern and only show it here for completeness.
Instead, it is preferable to avoid passing callbacks deep down.
Under the Hood
How does React associate Hook calls with components?
React keeps track of the currently rendering component.
Thanks to the Rules of Hooks, we know that Hooks are only called from React components (or custom Hooks ¡ª which are also only called from React components).
There is an internal list of ¡°memory cells¡± associated with each component.
They're just JavaScript objects where we can put some data.
When you call a Hook like useState()
, it reads the current cell (or initializes it during the first render), and then moves the pointer to the next one.
This is how multiple useState()
calls each get independent local state.
What is the prior art for Hooks?
Hooks synthesize ideas from several different sources:
- Our old experiments with functional APIs in the react-future repository.
- React community's experiments with render prop APIs, including Ryan Florence's Reactions Component.
-
Dominic Gannaway's
adopt
keyword proposal as a sugar syntax for render props.
- State variables and state cells in DisplayScript.
-
Reducer components in ReasonReact.
-
Subscriptions in Rx.
-
Algebraic effects in Multicore OCaml.
Sebastian Markb ge came up with the original design for Hooks, later refined by Andrew Clark, Sophie Alpert, Dominic Gannaway, and other members of the React team.
Testing Overview
You can test React components similar to testing other JavaScript code.
There are a few ways to test React components.
Broadly, they divide into two categories:
-
Rendering component trees in a simplified test environment and asserting on their output.
-
Running a complete app in a realistic browser environment (also known as ¡°end-to-end¡± tests).
This documentation section focuses on testing strategies for the first case.
While full end-to-end tests can be very useful to prevent regressions to important workflows, such tests are not concerned with React components in particular, and are out of the scope of this section.
Tradeoffs
When choosing testing tools, it is worth considering a few tradeoffs:
-
Iteration speed vs Realistic environment: Some tools offer a very quick feedback loop between making a change and seeing the result, but don't model the browser behavior precisely.
Other tools might use a real browser environment, but reduce the iteration speed and are flakier on a continuous integration server.
-
How much to mock: With components, the distinction between a ¡°unit¡± and ¡°integration¡± test can be blurry.
If you're testing a form, should its test also test the buttons inside of it? Or should a button component have its own test suite? Should refactoring a button ever break the form test?
Different answers may work for different teams and products.
Recommended Tools
Jest is a JavaScript test runner that lets you access the DOM via jsdom
.
While jsdom is only an approximation of how the browser works, it is often good enough for testing React components.
Jest provides a great iteration speed combined with powerful features like mocking modules and timers so you can have more control over how the code executes.
React Testing Library is a set of helpers that let you test React components without relying on their implementation details.
This approach makes refactoring a breeze and also nudges you towards best practices for accessibility.
Although it doesn't provide a way to ¡°shallowly¡± render a component without its children, a test runner like Jest lets you do this by mocking.
Learn More
This section is divided in two pages:
-
Recipes: Common patterns when writing tests for React components.
-
Environments: What to consider when setting up a testing environment for React components.
Testing Recipes
Common testing patterns for React components.
Note:
This page assumes you're using Jest as a test runner.
If you use a different test runner, you may need to adjust the API, but the overall shape of the solution will likely be the same.
Read more details on setting up a testing environment on the Testing Environments page.
On this page, we will primarily use function components.
However, these testing strategies don't depend on implementation details, and work just as well for class components too.
- Setup/Teardown
act()
- Rendering
- Data Fetching
- Mocking Modules
- Events
- Timers
- Snapshot Testing
- Multiple Renderers
- Something Missing?
Setup/Teardown
For each test, we usually want to render our React tree to a DOM element that's attached to document
.
This is important so that it can receive DOM events.
When the test ends, we want to ¡°clean up¡± and unmount the tree from the document
.
A common way to do it is to use a pair of beforeEach
and afterEach
blocks so that they'll always run and isolate the effects of a test to itself:
import { unmountComponentAtNode } from "react-dom";
let container = null;
beforeEach(() => {
// setup a DOM element as a render target
container = document.createElement("div");
document.body.appendChild(container);
});
afterEach(() => {
// cleanup on exiting
unmountComponentAtNode(container);
container.remove();
container = null;
});
You may use a different pattern, but keep in mind that we want to execute the cleanup even if a test fails.
Otherwise, tests can become ¡°leaky¡±, and one test can change the behavior of another test.
That makes them difficult to debug.
act()
When writing UI tests, tasks like rendering, user events, or data fetching can be considered as ¡°units¡± of interaction with a user interface.
react-dom/test-utils
provides a helper called act()
that makes sure all updates related to these ¡°units¡± have been processed and applied to the DOM before you make any assertions:
act(() => {
// render components
});
// make assertions
This helps make your tests run closer to what real users would experience when using your application.
The rest of these examples use act()
to make these guarantees.
You might find using act()
directly a bit too verbose.
To avoid some of the boilerplate, you could use a library like React Testing Library, whose helpers are wrapped with act()
.
Note:
The name act
comes from the Arrange-Act-Assert pattern.
Rendering
Commonly, you might want to test whether a component renders correctly for given props.
Consider a simple component that renders a message based on a prop:
// hello.js
import React from "react";
export default function Hello(props) {
if (props.name) {
return <h2>Hello, {props.name}!</h2>;
} else {
return <span>Hey, stranger</span>;
}
}
We can write a test for this component:
// hello.test.js
import React from "react";
import { render, unmountComponentAtNode } from "react-dom";
import { act } from "react-dom/test-utils";
import Hello from "./hello";
let container = null;
beforeEach(() => {
// setup a DOM element as a render target
container = document.createElement("div");
document.body.appendChild(container);
});
afterEach(() => {
// cleanup on exiting
unmountComponentAtNode(container);
container.remove();
container = null;
});
it("renders with or without a name", () => {
act(() => { render(<Hello />, container); }); expect(container.textContent).toBe("Hey, stranger");
act(() => {
render(<Hello name="Jenny" />, container);
});
expect(container.textContent).toBe("Hello, Jenny!");
act(() => {
render(<Hello name="Margaret" />, container);
});
expect(container.textContent).toBe("Hello, Margaret!");
});
Data Fetching
Instead of calling real APIs in all your tests, you can mock requests with dummy data.
Mocking data fetching with ¡°fake¡± data prevents flaky tests due to an unavailable backend, and makes them run faster.
Note: you may still want to run a subset of tests using an ¡°end-to-end¡± framework that tells whether the whole app is working together.
// user.js
import React, { useState, useEffect } from "react";
export default function User(props) {
const [user, setUser] = useState(null);
async function fetchUserData(id) {
const response = await fetch("/" + id);
setUser(await response.json());
}
useEffect(() => {
fetchUserData(props.id);
}, [props.id]);
if (!user) {
return "loading...";
}
return (
<details>
<summary>{user.name}</summary>
<strong>{user.age}</strong> years old
<br />
lives in {user.address}
</details>
);
}
We can write tests for it:
// user.test.js
import React from "react";
import { render, unmountComponentAtNode } from "react-dom";
import { act } from "react-dom/test-utils";
import User from "./user";
let container = null;
beforeEach(() => {
// setup a DOM element as a render target
container = document.createElement("div");
document.body.appendChild(container);
});
afterEach(() => {
// cleanup on exiting
unmountComponentAtNode(container);
container.remove();
container = null;
});
it("renders user data", async () => {
const fakeUser = { name: "Joni Baez", age: "32", address: "123, Charming Avenue" }; jest.spyOn(global, "fetch").mockImplementation(() => Promise.resolve({ json: () => Promise.resolve(fakeUser) }) );
// Use the asynchronous version of act to apply resolved promises
await act(async () => {
render(<User id="123" />, container);
});
expect(container.querySelector("summary").textContent).toBe(fakeUser.name);
expect(container.querySelector("strong").textContent).toBe(fakeUser.age);
expect(container.textContent).toContain(fakeUser.address);
// remove the mock to ensure tests are completely isolated global.fetch.mockRestore();});
Mocking Modules
Some modules might not work well inside a testing environment, or may not be as essential to the test itself.
Mocking out these modules with dummy replacements can make it easier to write tests for your own code.
Consider a Contact
component that embeds a third-party GoogleMap
component:
// map.js
import React from "react";
import { LoadScript, GoogleMap } from "react-google-maps";
export default function Map(props) {
return (
<LoadScript id="script-loader" googleMapsApiKey="YOUR_API_KEY">
<GoogleMap id="example-map" center={props.center} />
</LoadScript>
);
}
// contact.js
import React from "react";
import Map from "./map";
export default function Contact(props) {
return (
<div>
<address>
Contact {props.name} via{" "}
<a data-testid="email" href={"mailto:" + props.email}>
email
</a>
or on their <a data-testid="site" href={props.site}>
website
</a>.
</address>
<Map center={props.center} />
</div>
);
}
If we don't want to load this component in our tests, we can mock out the dependency itself to a dummy component, and run our tests:
// contact.test.js
import React from "react";
import { render, unmountComponentAtNode } from "react-dom";
import { act } from "react-dom/test-utils";
import Contact from "./contact";
import MockedMap from "./map";
jest.mock("./map", () => { return function DummyMap(props) { return ( <div data-testid="map"> {props.center.lat}:{props.center.long} </div> ); };});
let container = null;
beforeEach(() => {
// setup a DOM element as a render target
container = document.createElement("div");
document.body.appendChild(container);
});
afterEach(() => {
// cleanup on exiting
unmountComponentAtNode(container);
container.remove();
container = null;
});
it("should render contact information", () => {
const center = { lat: 0, long: 0 };
act(() => {
render(
<Contact
name="Joni Baez"
email="test@example.com"
site="http://test.com"
center={center}
/>,
container
);
});
expect(
container.querySelector("[data-testid='email']").getAttribute("href")
).toEqual("mailto:test@example.com");
expect(
container.querySelector('[data-testid="site"]').getAttribute("href")
).toEqual("http://test.com");
expect(container.querySelector('[data-testid="map"]').textContent).toEqual(
"0:0"
);
});
Events
We recommend dispatching real DOM events on DOM elements, and then asserting on the result.
Consider a Toggle
component:
// toggle.js
import React, { useState } from "react";
export default function Toggle(props) {
const [state, setState] = useState(false);
return (
<button
onClick={() => {
setState(previousState => !previousState);
props.onChange(!state);
}}
data-testid="toggle"
>
{state === true ? "Turn off" : "Turn on"}
</button>
);
}
We could write tests for it:
// toggle.test.js
import React from "react";
import { render, unmountComponentAtNode } from "react-dom";
import { act } from "react-dom/test-utils";
import Toggle from "./toggle";
let container = null;
beforeEach(() => {
// setup a DOM element as a render target
container = document.createElement("div");
document.body.appendChild(container);});
afterEach(() => {
// cleanup on exiting
unmountComponentAtNode(container);
container.remove();
container = null;
});
it("changes value when clicked", () => {
const onChange = jest.fn();
act(() => {
render(<Toggle onChange={onChange} />, container);
});
// get ahold of the button element, and trigger some clicks on it
const button = document.querySelector("[data-testid=toggle]");
expect(button.innerHTML).toBe("Turn on");
act(() => {
button.dispatchEvent(new MouseEvent("click", { bubbles: true }));
});
expect(onChange).toHaveBeenCalledTimes(1);
expect(button.innerHTML).toBe("Turn off");
act(() => {
for (let i = 0; i < 5; i++) {
button.dispatchEvent(new MouseEvent("click", { bubbles: true }));
} });
expect(onChange).toHaveBeenCalledTimes(6);
expect(button.innerHTML).toBe("Turn on");
});
Different DOM events and their properties are described in MDN.
Note that you need to pass { bubbles: true }
in each event you create for it to reach the React listener because React automatically delegates events to the root.
Note:
React Testing Library offers a more concise helper for firing events.
Timers
Your code might use timer-based functions like setTimeout
to schedule more work in the future.
In this example, a multiple choice panel waits for a selection and advances, timing out if a selection isn't made in 5 seconds:
// card.js
import React, { useEffect } from "react";
export default function Card(props) {
useEffect(() => {
const timeoutID = setTimeout(() => {
props.onSelect(null);
}, 5000);
return () => {
clearTimeout(timeoutID);
};
}, [props.onSelect]);
return [1, 2, 3, 4].map(choice => (
<button
key={choice}
data-testid={choice}
onClick={() => props.onSelect(choice)}
>
{choice}
</button>
));
}
We can write tests for this component by leveraging Jest's timer mocks, and testing the different states it can be in.
// card.test.js
import React from "react";
import { render, unmountComponentAtNode } from "react-dom";
import { act } from "react-dom/test-utils";
import Card from "./card";
jest.useFakeTimers();
let container = null;
beforeEach(() => {
// setup a DOM element as a render target
container = document.createElement("div");
document.body.appendChild(container);
});
afterEach(() => {
// cleanup on exiting
unmountComponentAtNode(container);
container.remove();
container = null;
});
it("should select null after timing out", () => {
const onSelect = jest.fn();
act(() => {
render(<Card onSelect={onSelect} />, container);
});
// move ahead in time by 100ms act(() => {
jest.advanceTimersByTime(100);
});
expect(onSelect).not.toHaveBeenCalled();
// and then move ahead by 5 seconds act(() => {
jest.advanceTimersByTime(5000);
});
expect(onSelect).toHaveBeenCalledWith(null);
});
it("should cleanup on being removed", () => {
const onSelect = jest.fn();
act(() => {
render(<Card onSelect={onSelect} />, container);
});
act(() => {
jest.advanceTimersByTime(100);
});
expect(onSelect).not.toHaveBeenCalled();
// unmount the app
act(() => {
render(null, container);
});
act(() => {
jest.advanceTimersByTime(5000);
});
expect(onSelect).not.toHaveBeenCalled();
});
it("should accept selections", () => {
const onSelect = jest.fn();
act(() => {
render(<Card onSelect={onSelect} />, container);
});
act(() => {
container
.querySelector("[data-testid='2']")
.dispatchEvent(new MouseEvent("click", { bubbles: true }));
});
expect(onSelect).toHaveBeenCalledWith(2);
});
You can use fake timers only in some tests.
Above, we enabled them by calling jest.useFakeTimers()
.
The main advantage they provide is that your test doesn't actually have to wait five seconds to execute, and you also didn't need to make the component code more convoluted just for testing.
Snapshot Testing
Frameworks like Jest also let you save ¡°snapshots¡± of data with toMatchSnapshot
/ toMatchInlineSnapshot
.
With these, we can ¡°save¡± the rendered component output and ensure that a change to it has to be explicitly committed as a change to the snapshot.
In this example, we render a component and format the rendered HTML with the pretty
package, before saving it as an inline snapshot:
// hello.test.js, again
import React from "react";
import { render, unmountComponentAtNode } from "react-dom";
import { act } from "react-dom/test-utils";
import pretty from "pretty";
import Hello from "./hello";
let container = null;
beforeEach(() => {
// setup a DOM element as a render target
container = document.createElement("div");
document.body.appendChild(container);
});
afterEach(() => {
// cleanup on exiting
unmountComponentAtNode(container);
container.remove();
container = null;
});
it("should render a greeting", () => {
act(() => {
render(<Hello />, container);
});
expect( pretty(container.innerHTML) ).toMatchInlineSnapshot(); /* ...
gets filled automatically by jest ...
*/
act(() => {
render(<Hello name="Jenny" />, container);
});
expect(
pretty(container.innerHTML)
).toMatchInlineSnapshot(); /* ...
gets filled automatically by jest ...
*/
act(() => {
render(<Hello name="Margaret" />, container);
});
expect(
pretty(container.innerHTML)
).toMatchInlineSnapshot(); /* ...
gets filled automatically by jest ...
*/
});
It's typically better to make more specific assertions than to use snapshots.
These kinds of tests include implementation details so they break easily, and teams can get desensitized to snapshot breakages.
Selectively mocking some child components can help reduce the size of snapshots and keep them readable for the code review.
Multiple Renderers
In rare cases, you may be running a test on a component that uses multiple renderers.
For example, you may be running snapshot tests on a component with react-test-renderer
, that internally uses ReactDOM.render
inside a child component to render some content.
In this scenario, you can wrap updates with act()
s corresponding to their renderers.
import { act as domAct } from "react-dom/test-utils";
import { act as testAct, create } from "react-test-renderer";
// ...
let root;
domAct(() => {
testAct(() => {
root = create(<App />);
});
});
expect(root).toMatchSnapshot();
Something Missing?
If some common scenario is not covered, please let us know on the issue tracker for the documentation website.
Testing Environments
This document goes through the factors that can affect your environment and recommendations for some scenarios.
Test runners
Test runners like Jest, mocha, ava let you write test suites as regular JavaScript, and run them as part of your development process.
Additionally, test suites are run as part of continuous integration.
- Jest is widely compatible with React projects, supporting features like mocked modules and timers, and
jsdom
support.
If you use Create React App, Jest is already included out of the box with useful defaults.
- Libraries like mocha work well in real browser environments, and could help for tests that explicitly need it.
- End-to-end tests are used for testing longer flows across multiple pages, and require a different setup.
Mocking a rendering surface
Tests often run in an environment without access to a real rendering surface like a browser.
For these environments, we recommend simulating a browser with jsdom
, a lightweight browser implementation that runs inside Node.js.
In most cases, jsdom behaves like a regular browser would, but doesn't have features like layout and navigation.
This is still useful for most web-based component tests, since it runs quicker than having to start up a browser for each test.
It also runs in the same process as your tests, so you can write code to examine and assert on the rendered DOM.
Just like in a real browser, jsdom lets us model user interactions; tests can dispatch events on DOM nodes, and then observe and assert on the side effects of these actions (example).
A large portion of UI tests can be written with the above setup: using Jest as a test runner, rendered to jsdom, with user interactions specified as sequences of browser events, powered by the act()
helper (example).
For example, a lot of React's own tests are written with this combination.
If you're writing a library that tests mostly browser-specific behavior, and requires native browser behavior like layout or real inputs, you could use a framework like mocha.
In an environment where you can't simulate a DOM (e.g.
testing React Native components on Node.js), you could use event simulation helpers to simulate interactions with elements.
Alternately, you could use the fireEvent
helper from @testing-library/react-native
.
Frameworks like Cypress, puppeteer and webdriver are useful for running end-to-end tests.
Mocking functions
When writing tests, we'd like to mock out the parts of our code that don't have equivalents inside our testing environment (e.g.
checking navigator.onLine
status inside Node.js).
Tests could also spy on some functions, and observe how other parts of the test interact with them.
It is then useful to be able to selectively mock these functions with test-friendly versions.
This is especially useful for data fetching.
It is usually preferable to use ¡°fake¡± data for tests to avoid the slowness and flakiness due to fetching from real API endpoints (example).
This helps make the tests predictable.
Libraries like Jest and sinon, among others, support mocked functions.
For end-to-end tests, mocking network can be more difficult, but you might also want to test the real API endpoints in them anyway.
Mocking modules
Some components have dependencies for modules that may not work well in test environments, or aren't essential to our tests.
It can be useful to selectively mock these modules out with suitable replacements (example).
On Node.js, runners like Jest support mocking modules.
You could also use libraries like mock-require
.
Mocking timers
Components might be using time-based functions like setTimeout
, setInterval
, or Date.now
.
In testing environments, it can be helpful to mock these functions out with replacements that let you manually ¡°advance¡± time.
This is great for making sure your tests run fast! Tests that are dependent on timers would still resolve in order, but quicker (example).
Most frameworks, including Jest, sinon and lolex, let you mock timers in your tests.
Sometimes, you may not want to mock timers.
For example, maybe you're testing an animation, or interacting with an endpoint that's sensitive to timing (like an API rate limiter).
Libraries with timer mocks let you enable and disable them on a per test/suite basis, so you can explicitly choose how these tests would run.
End-to-end tests
End-to-end tests are useful for testing longer workflows, especially when they're critical to your business (such as payments or signups).
For these tests, you'd probably want to test how a real browser renders the whole app, fetches data from the real API endpoints, uses sessions and cookies, navigates between different links.
You might also likely want to make assertions not just on the DOM state, but on the backing data as well (e.g.
to verify whether the updates have been persisted to the database).
In this scenario, you would use a framework like Cypress or a library like puppeteer so you can navigate between multiple routes and assert on side effects not just in the browser, but potentially on the backend as well.
Introducing Concurrent Mode (Experimental)
Caution:
This page describes experimental features that are not yet available in a stable release.
Don't rely on experimental builds of React in production apps.
These features may change significantly and without a warning before they become a part of React.
This documentation is aimed at early adopters and people who are curious.
If you're new to React, don't worry about these features ¡ª you don't need to learn them right now.
This page provides a theoretical overview of Concurrent Mode.
For a more practical introduction, you might want to check out the next sections:
-
Suspense for Data Fetching describes a new mechanism for fetching data in React components.
-
Concurrent UI Patterns shows some UI patterns made possible by Concurrent Mode and Suspense.
-
Adopting Concurrent Mode explains how you can try Concurrent Mode in your project.
-
Concurrent Mode API Reference documents the new APIs available in experimental builds.
What Is Concurrent Mode?
Concurrent Mode is a set of new features that help React apps stay responsive and gracefully adjust to the user's device capabilities and network speed.
These features are still experimental and are subject to change.
They are not yet a part of a stable React release, but you can try them in an experimental build.
Blocking vs Interruptible Rendering
To explain Concurrent Mode, we'll use version control as a metaphor. If you work on a team, you probably use a version control system like Git and work on branches.
When a branch is ready, you can merge your work into master so that other people can pull it.
Before version control existed, the development workflow was very different.
There was no concept of branches.
If you wanted to edit some files, you had to tell everyone not to touch those files until you've finished your work.
You couldn't even start working on them concurrently with that person ¡ª you were literally blocked by them.
This illustrates how UI libraries, including React, typically work today.
Once they start rendering an update, including creating new DOM nodes and running the code inside components, they can't interrupt this work.
We'll call this approach ¡°blocking rendering¡±.
In Concurrent Mode, rendering is not blocking.
It is interruptible.
This improves the user experience.
It also unlocks new features that weren't possible before.
Before we look at concrete examples in the next chapters, we'll do a high-level overview of new features.
Interruptible Rendering
Consider a filterable product list.
Have you ever typed into a list filter and felt that it stutters on every key press? Some of the work to update the product list might be unavoidable, such as creating new DOM nodes or the browser performing layout.
However, when and how we perform that work plays a big role.
A common way to work around the stutter is to ¡°debounce¡± the input.
When debouncing, we only update the list after the user stops typing.
However, it can be frustrating that the UI doesn't update while we're typing.
As an alternative, we could ¡°throttle¡± the input, and update the list with a certain maximum frequency.
But then on lower-powered devices we'd still end up with stutter.
Both debouncing and throttling create a suboptimal user experience.
The reason for the stutter is simple: once rendering begins, it can't be interrupted.
So the browser can't update the text input right after the key press.
No matter how good a UI library (such as React) might look on a benchmark, if it uses blocking rendering, a certain amount of work in your components will always cause stutter.
And, often, there is no easy fix.
Concurrent Mode fixes this fundamental limitation by making rendering interruptible. This means when the user presses another key, React doesn't need to block the browser from updating the text input.
Instead, it can let the browser paint an update to the input, and then continue rendering the updated list in memory.
When the rendering is finished, React updates the DOM, and changes are reflected on the screen.
Conceptually, you can think of this as React preparing every update ¡°on a branch¡±.
Just like you can abandon work in branches or switch between them, React in Concurrent Mode can interrupt an ongoing update to do something more important, and then come back to what it was doing earlier.
This technique might also remind you of double buffering in video games.
Concurrent Mode techniques reduce the need for debouncing and throttling in UI.
Because rendering is interruptible, React doesn't need to artificially delay work to avoid stutter.
It can start rendering right away, but interrupt this work when needed to keep the app responsive.
Intentional Loading Sequences
We've said before that Concurrent Mode is like React working ¡°on a branch¡±.
Branches are useful not only for short-term fixes, but also for long-running features.
Sometimes you might work on a feature, but it could take weeks before it's in a ¡°good enough state¡± to merge into master.
This side of our version control metaphor applies to rendering too.
Imagine we're navigating between two screens in an app.
Sometimes, we might not have enough code and data loaded to show a ¡°good enough¡± loading state to the user on the new screen.
Transitioning to an empty screen or a large spinner can be a jarring experience.
However, it's also common that the necessary code and data doesn't take too long to fetch.
Wouldn't it be nicer if React could stay on the old screen for a little longer, and ¡°skip¡± the ¡°bad loading state¡± before showing the new screen?
While this is possible today, it can be difficult to orchestrate.
In Concurrent Mode, this feature is built-in.
React starts preparing the new screen in memory first ¡ª or, as our metaphor goes, ¡°on a different branch¡±.
So React can wait before updating the DOM so that more content can load.
In Concurrent Mode, we can tell React to keep showing the old screen, fully interactive, with an inline loading indicator.
And when the new screen is ready, React can take us to it.
Concurrency
Let's recap the two examples above and see how Concurrent Mode unifies them.
In Concurrent Mode, React can work on several state updates concurrently ¡ª just like branches let different team members work independently:
- For CPU-bound updates (such as creating DOM nodes and running component code), concurrency means that a more urgent update can ¡°interrupt¡± rendering that has already started.
- For IO-bound updates (such as fetching code or data from the network), concurrency means that React can start rendering in memory even before all the data arrives, and skip showing jarring empty loading states.
Importantly, the way you use React is the same.
Concepts like components, props, and state fundamentally work the same way.
When you want to update the screen, you set the state.
React uses a heuristic to decide how ¡°urgent¡± an update is, and lets you adjust it with a few lines of code so that you can achieve the desired user experience for every interaction.
Putting Research into Production
There is a common theme around Concurrent Mode features.
Its mission is to help integrate the findings from the Human-Computer Interaction research into real UIs.
For example, research shows that displaying too many intermediate loading states when transitioning between screens makes a transition feel slower.
This is why Concurrent Mode shows new loading states on a fixed ¡°schedule¡± to avoid jarring and too frequent updates.
Similarly, we know from research that interactions like hover and text input need to be handled within a very short period of time, while clicks and page transitions can wait a little longer without feeling laggy.
The different ¡°priorities¡± that Concurrent Mode uses internally roughly correspond to the interaction categories in the human perception research.
Teams with a strong focus on user experience sometimes solve similar problems with one-off solutions.
However, those solutions rarely survive for a long time, as they're hard to maintain.
With Concurrent Mode, our goal is to bake the UI research findings into the abstraction itself, and provide idiomatic ways to use them.
As a UI library, React is well-positioned to do that.
Next Steps
Now you know what Concurrent Mode is all about!
On the next pages, you'll learn more details about specific topics:
-
Suspense for Data Fetching describes a new mechanism for fetching data in React components.
-
Concurrent UI Patterns shows some UI patterns made possible by Concurrent Mode and Suspense.
-
Adopting Concurrent Mode explains how you can try Concurrent Mode in your project.
-
Concurrent Mode API Reference documents the new APIs available in experimental builds.
Suspense for Data Fetching (Experimental)
Caution:
This page describes experimental features that are not yet available in a stable release.
Don't rely on experimental builds of React in production apps.
These features may change significantly and without a warning before they become a part of React.
This documentation is aimed at early adopters and people who are curious.
If you're new to React, don't worry about these features ¡ª you don't need to learn them right now.
For example, if you're looking for a data fetching tutorial that works today, read this article instead.
React 16.6 added a <Suspense>
component that lets you ¡°wait¡± for some code to load and declaratively specify a loading state (like a spinner) while we're waiting:
const ProfilePage = React.lazy(() => import('./ProfilePage')); // Lazy-loaded
// Show a spinner while the profile is loading
<Suspense fallback={<Spinner />}>
<ProfilePage />
</Suspense>
Suspense for Data Fetching is a new feature that lets you also use <Suspense>
to declaratively ¡°wait¡± for anything else, including data. This page focuses on the data fetching use case, but it can also wait for images, scripts, or other asynchronous work.
-
What Is Suspense, Exactly?
- What Suspense Is Not
- What Suspense Lets You Do
-
Using Suspense in Practice
- What If I Don't Use Relay?
- For Library Authors
-
Traditional Approaches vs Suspense
- Approach 1: Fetch-on-Render (not using Suspense)
- Approach 2: Fetch-Then-Render (not using Suspense)
- Approach 3: Render-as-You-Fetch (using Suspense)
-
Start Fetching Early
- We're Still Figuring This Out
-
Suspense and Race Conditions
- Race Conditions with useEffect
- Race Conditions with componentDidUpdate
- The Problem
- Solving Race Conditions with Suspense
- Handling Errors
- Next Steps
What Is Suspense, Exactly?
Suspense lets your components ¡°wait¡± for something before they can render.
In this example, two components wait for an asynchronous API call to fetch some data:
const resource = fetchProfileData();
function ProfilePage() {
return (
<Suspense fallback={<h2>Loading profile...</h2>}>
<ProfileDetails />
<Suspense fallback={<h2>Loading posts...</h2>}>
<ProfileTimeline />
</Suspense>
</Suspense>
);
}
function ProfileDetails() {
// Try to read user info, although it might not have loaded yet
const user = resource.user.read();
return <h2>{user.name}</h2>;
}
function ProfileTimeline() {
// Try to read posts, although they might not have loaded yet
const posts = resource.posts.read();
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
Try it on CodeSandbox
This demo is a teaser.
Don't worry if it doesn't quite make sense yet.
We'll talk more about how it works below.
Keep in mind that Suspense is more of a mechanism, and particular APIs like fetchProfileData()
or resource.posts.read()
in the above example are not very important.
If you're curious, you can find their definitions right in the demo sandbox.
Suspense is not a data fetching library.
It's a mechanism for data fetching libraries to communicate to React that the data a component is reading is not ready yet.
React can then wait for it to be ready and update the UI.
At Facebook, we use Relay and its new Suspense integration.
We expect that other libraries like Apollo can provide similar integrations.
In the long term, we intend Suspense to become the primary way to read asynchronous data from components ¡ª no matter where that data is coming from.
What Suspense Is Not
Suspense is significantly different from existing approaches to these problems, so reading about it for the first time often leads to misconceptions.
Let's clarify the most common ones:
-
It is not a data fetching implementation. It does not assume that you use GraphQL, REST, or any other particular data format, library, transport, or protocol.
-
It is not a ready-to-use client. You can't ¡°replace¡±
fetch
or Relay with Suspense.
But you can use a library that's integrated with Suspense (for example, new Relay APIs).
-
It does not couple data fetching to the view layer. It helps orchestrate displaying the loading states in your UI, but it doesn't tie your network logic to React components.
What Suspense Lets You Do
So what's the point of Suspense? There are a few ways we can answer this:
-
It lets data fetching libraries deeply integrate with React. If a data fetching library implements Suspense support, using it from React components feels very natural.
-
It lets you orchestrate intentionally designed loading states. It doesn't say how the data is fetched, but it lets you closely control the visual loading sequence of your app.
-
It helps you avoid race conditions. Even with
await
, asynchronous code is often error-prone.
Suspense feels more like reading data synchronously ¡ª as if it were already loaded.
Using Suspense in Practice
At Facebook, so far we have only used the Relay integration with Suspense in production.
If you're looking for a practical guide to get started today, check out the Relay Guide! It demonstrates patterns that have already worked well for us in production.
The code demos on this page use a ¡°fake¡± API implementation rather than Relay. This makes them easier to understand if you're not familiar with GraphQL, but they won't tell you the ¡°right way¡± to build an app with Suspense.
This page is more conceptual and is intended to help you see why Suspense works in a certain way, and which problems it solves.
What If I Don't Use Relay?
If you don't use Relay today, you might have to wait before you can really try Suspense in your app.
So far, it's the only implementation that we tested in production and are confident in.
Over the next several months, many libraries will appear with different takes on Suspense APIs.
If you prefer to learn when things are more stable, you might prefer to ignore this work for now, and come back when the Suspense ecosystem is more mature.
You can also write your own integration for a data fetching library, if you'd like.
For Library Authors
We expect to see a lot of experimentation in the community with other libraries.
There is one important thing to note for data fetching library authors.
Although it's technically doable, Suspense is not currently intended as a way to start fetching data when a component renders.
Rather, it lets components express that they're ¡°waiting¡± for data that is already being fetched.
Building Great User Experiences with Concurrent Mode and Suspense describes why this matters and how to implement this pattern in practice.
Unless you have a solution that helps prevent waterfalls, we suggest to prefer APIs that favor or enforce fetching before render.
For a concrete example, you can look at how Relay Suspense API enforces preloading.
Our messaging about this hasn't been very consistent in the past.
Suspense for Data Fetching is still experimental, so you can expect our recommendations to change over time as we learn more from production usage and understand the problem space better.
Traditional Approaches vs Suspense
We could introduce Suspense without mentioning the popular data fetching approaches.
However, this makes it more difficult to see which problems Suspense solves, why these problems are worth solving, and how Suspense is different from the existing solutions.
Instead, we'll look at Suspense as a logical next step in a sequence of approaches:
-
Fetch-on-render (for example,
fetch
in useEffect
): Start rendering components.
Each of these components may trigger data fetching in their effects and lifecycle methods.
This approach often leads to ¡°waterfalls¡±.
-
Fetch-then-render (for example, Relay without Suspense): Start fetching all the data for the next screen as early as possible.
When the data is ready, render the new screen.
We can't do anything until the data arrives.
-
Render-as-you-fetch (for example, Relay with Suspense): Start fetching all the required data for the next screen as early as possible, and start rendering the new screen immediately ¡ª before we get a network response.
As data streams in, React retries rendering components that still need data until they're all ready.
Note
This is a bit simplified, and in practice solutions tend to use a mix of different approaches.
Still, we will look at them in isolation to better contrast their tradeoffs.
To compare these approaches, we'll implement a profile page with each of them.
Approach 1: Fetch-on-Render (not using Suspense)
A common way to fetch data in React apps today is to use an effect:
// In a function component:
useEffect(() => {
fetchSomething();
}, []);
// Or, in a class component:
componentDidMount() {
fetchSomething();
}
We call this approach ¡°fetch-on-render¡± because it doesn't start fetching until after the component has rendered on the screen.
This leads to a problem known as a ¡°waterfall¡±.
Consider these <ProfilePage>
and <ProfileTimeline>
components:
function ProfilePage() {
const [user, setUser] = useState(null);
useEffect(() => { fetchUser().then(u => setUser(u)); }, []);
if (user === null) {
return <p>Loading profile...</p>;
}
return (
<>
<h2>{user.name}</h2>
<ProfileTimeline />
</>
);
}
function ProfileTimeline() {
const [posts, setPosts] = useState(null);
useEffect(() => { fetchPosts().then(p => setPosts(p)); }, []);
if (posts === null) {
return <h3>Loading posts...</h3>;
}
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
Try it on CodeSandbox
If you run this code and watch the console logs, you'll notice the sequence is:
- We start fetching user details
- We wait¡
- We finish fetching user details
- We start fetching posts
- We wait¡
- We finish fetching posts
If fetching user details takes three seconds, we'll only start fetching the posts after three seconds! That's a ¡°waterfall¡±: an unintentional sequence that should have been parallelized.
Waterfalls are common in code that fetches data on render.
They're possible to solve, but as the product grows, many people prefer to use a solution that guards against this problem.
Approach 2: Fetch-Then-Render (not using Suspense)
Libraries can prevent waterfalls by offering a more centralized way to do data fetching.
For example, Relay solves this problem by moving the information about the data a component needs to statically analyzable fragments, which later get composed into a single query.
On this page, we don't assume knowledge of Relay, so we won't be using it for this example.
Instead, we'll write something similar manually by combining our data fetching methods:
function fetchProfileData() {
return Promise.all([
fetchUser(),
fetchPosts()
]).then(([user, posts]) => {
return {user, posts};
})
}
In this example, <ProfilePage>
waits for both requests but starts them in parallel:
// Kick off fetching as early as possibleconst promise = fetchProfileData();
function ProfilePage() {
const [user, setUser] = useState(null);
const [posts, setPosts] = useState(null);
useEffect(() => { promise.then(data => { setUser(data.user); setPosts(data.posts); }); }, []);
if (user === null) {
return <p>Loading profile...</p>;
}
return (
<>
<h2>{user.name}</h2>
<ProfileTimeline posts={posts} />
</>
);
}
// The child doesn't trigger fetching anymore
function ProfileTimeline({ posts }) {
if (posts === null) {
return <h3>Loading posts...</h3>;
}
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
Try it on CodeSandbox
The event sequence now becomes like this:
- We start fetching user details
- We start fetching posts
- We wait¡
- We finish fetching user details
- We finish fetching posts
We've solved the previous network ¡°waterfall¡±, but accidentally introduced a different one.
We wait for all data to come back with Promise.all()
inside fetchProfileData
, so now we can't render profile details until the posts have been fetched too.
We have to wait for both.
Of course, this is possible to fix in this particular example.
We could remove the Promise.all()
call, and wait for both Promises separately.
However, this approach gets progressively more difficult as the complexity of our data and component tree grows.
It's hard to write reliable components when arbitrary parts of the data tree may be missing or stale.
So fetching all data for the new screen and then rendering is often a more practical option.
Approach 3: Render-as-You-Fetch (using Suspense)
In the previous approach, we fetched data before we called setState
:
- Start fetching
- Finish fetching
- Start rendering
With Suspense, we still start fetching first, but we flip the last two steps around:
- Start fetching
- Start rendering
- Finish fetching
With Suspense, we don't wait for the response to come back before we start rendering. In fact, we start rendering pretty much immediately after kicking off the network request:
// This is not a Promise.
It's a special object from our Suspense integration.
const resource = fetchProfileData();
function ProfilePage() {
return (
<Suspense fallback={<h2>Loading profile...</h2>}>
<ProfileDetails />
<Suspense fallback={<h2>Loading posts...</h2>}>
<ProfileTimeline />
</Suspense>
</Suspense>
);
}
function ProfileDetails() {
// Try to read user info, although it might not have loaded yet
const user = resource.user.read(); return <h2>{user.name}</h2>;
}
function ProfileTimeline() {
// Try to read posts, although they might not have loaded yet
const posts = resource.posts.read(); return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
Try it on CodeSandbox
Here's what happens when we render <ProfilePage>
on the screen:
- We've already kicked off the requests in
fetchProfileData()
.
It gave us a special ¡°resource¡± instead of a Promise.
In a realistic example, it would be provided by our data library's Suspense integration, like Relay.
- React tries to render
<ProfilePage>
.
It returns <ProfileDetails>
and <ProfileTimeline>
as children.
- React tries to render
<ProfileDetails>
.
It calls resource.user.read()
.
None of the data is fetched yet, so this component ¡°suspends¡±.
React skips over it, and tries rendering other components in the tree.
- React tries to render
<ProfileTimeline>
.
It calls resource.posts.read()
.
Again, there's no data yet, so this component also ¡°suspends¡±.
React skips over it too, and tries rendering other components in the tree.
- There's nothing left to try rendering.
Because
<ProfileDetails>
suspended, React shows the closest <Suspense>
fallback above it in the tree: <h2>Loading profile...</h2>
.
We're done for now.
This resource
object represents the data that isn't there yet, but might eventually get loaded.
When we call read()
, we either get the data, or the component ¡°suspends¡±.
As more data streams in, React will retry rendering, and each time it might be able to progress ¡°deeper¡±. When resource.user
is fetched, the <ProfileDetails>
component will render successfully and we'll no longer need the <h2>Loading profile...</h2>
fallback.
Eventually, we'll get all the data, and there will be no fallbacks on the screen.
This has an interesting implication.
Even if we use a GraphQL client that collects all data requirements in a single request, streaming the response lets us show more content sooner.
Because we render-as-we-fetch (as opposed to after fetching), if user
appears in the response earlier than posts
, we'll be able to ¡°unlock¡± the outer <Suspense>
boundary before the response even finishes.
We might have missed this earlier, but even the fetch-then-render solution contained a waterfall: between fetching and rendering.
Suspense doesn't inherently suffer from this waterfall, and libraries like Relay take advantage of this.
Note how we eliminated the if (...)
¡°is loading¡± checks from our components.
This doesn't only remove boilerplate code, but it also simplifies making quick design changes.
For example, if we wanted profile details and posts to always ¡°pop in¡± together, we could delete the <Suspense>
boundary between them.
Or we could make them independent from each other by giving each its own <Suspense>
boundary.
Suspense lets us change the granularity of our loading states and orchestrate their sequencing without invasive changes to our code.
Start Fetching Early
If you're working on a data fetching library, there's a crucial aspect of Render-as-You-Fetch you don't want to miss.
We kick off fetching before rendering. Look at this code example closer:
// Start fetching early!
const resource = fetchProfileData();
// ...
function ProfileDetails() {
// Try to read user info
const user = resource.user.read();
return <h2>{user.name}</h2>;
}
Try it on CodeSandbox
Note that the read()
call in this example doesn't start fetching.
It only tries to read the data that is already being fetched.
This difference is crucial to creating fast applications with Suspense.
We don't want to delay loading data until a component starts rendering.
As a data fetching library author, you can enforce this by making it impossible to get a resource
object without also starting a fetch.
Every demo on this page using our ¡°fake API¡± enforces this.
You might object that fetching ¡°at the top level¡± like in this example is impractical.
What are we going to do if we navigate to another profile's page? We might want to fetch based on props.
The answer to this is we want to start fetching in the event handlers instead.
Here is a simplified example of navigating between user's pages:
// First fetch: as soon as possibleconst initialResource = fetchProfileData(0);
function App() {
const [resource, setResource] = useState(initialResource);
return (
<>
<button onClick={() => {
const nextUserId = getNextId(resource.userId);
// Next fetch: when the user clicks setResource(fetchProfileData(nextUserId)); }}>
Next
</button>
<ProfilePage resource={resource} />
</>
);
}
Try it on CodeSandbox
With this approach, we can fetch code and data in parallel.
When we navigate between pages, we don't need to wait for a page's code to load to start loading its data.
We can start fetching both code and data at the same time (during the link click), delivering a much better user experience.
This poses a question of how do we know what to fetch before rendering the next screen.
There are several ways to solve this (for example, by integrating data fetching closer with your routing solution).
If you work on a data fetching library, Building Great User Experiences with Concurrent Mode and Suspense presents a deep dive on how to accomplish this and why it's important.
We're Still Figuring This Out
Suspense itself as a mechanism is flexible and doesn't have many constraints.
Product code needs to be more constrained to ensure no waterfalls, but there are different ways to provide these guarantees.
Some questions that we're currently exploring include:
- Fetching early can be cumbersome to express.
How do we make it easier to avoid waterfalls?
- When we fetch data for a page, can the API encourage including data for instant transitions from it?
- What is the lifetime of a response? Should caching be global or local? Who manages the cache?
- Can Proxies help express lazy-loaded APIs without inserting
read()
calls everywhere?
- What would the equivalent of composing GraphQL queries look like for arbitrary Suspense data?
Relay has its own answers to some of these questions.
There is certainly more than a single way to do it, and we're excited to see what new ideas the React community comes up with.
Suspense and Race Conditions
Race conditions are bugs that happen due to incorrect assumptions about the order in which our code may run.
Fetching data in the useEffect
Hook or in class lifecycle methods like componentDidUpdate
often leads to them.
Suspense can help here, too ¡ª let's see how.
To demonstrate the issue, we will add a top-level <App>
component that renders our <ProfilePage>
with a button that lets us switch between different profiles:
function getNextId(id) {
// ...
}
function App() {
const [id, setId] = useState(0);
return (
<>
<button onClick={() => setId(getNextId(id))}> Next </button> <ProfilePage id={id} />
</>
);
}
Let's compare how different data fetching strategies deal with this requirement.
Race Conditions with useEffect
First, we'll try a version of our original ¡°fetch in effect¡± example.
We'll modify it to pass an id
parameter from the <ProfilePage>
props to fetchUser(id)
and fetchPosts(id)
:
function ProfilePage({ id }) { const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(id).then(u => setUser(u)); }, [id]);
if (user === null) {
return <p>Loading profile...</p>;
}
return (
<>
<h2>{user.name}</h2>
<ProfileTimeline id={id} /> </>
);
}
function ProfileTimeline({ id }) { const [posts, setPosts] = useState(null);
useEffect(() => {
fetchPosts(id).then(p => setPosts(p)); }, [id]);
if (posts === null) {
return <h3>Loading posts...</h3>;
}
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
Try it on CodeSandbox
Note how we also changed the effect dependencies from []
to [id]
¡ª because we want the effect to re-run when the id
changes.
Otherwise, we wouldn't refetch new data.
If we try this code, it might seem like it works at first.
However, if we randomize the delay time in our ¡°fake API¡± implementation and press the ¡°Next¡± button fast enough, we'll see from the console logs that something is going very wrong.
Requests from the previous profiles may sometimes ¡°come back¡± after we've already switched the profile to another ID ¡ª and in that case they can overwrite the new state with a stale response for a different ID.
This problem is possible to fix (you could use the effect cleanup function to either ignore or cancel stale requests), but it's unintuitive and difficult to debug.
Race Conditions with componentDidUpdate
One might think that this is a problem specific to useEffect
or Hooks.
Maybe if we port this code to classes or use convenient syntax like async
/ await
, it will solve the problem?
Let's try that:
class ProfilePage extends React.Component {
state = {
user: null,
};
componentDidMount() {
this.fetchData(this.props.id);
}
componentDidUpdate(prevProps) {
if (prevProps.id !== this.props.id) {
this.fetchData(this.props.id);
}
}
async fetchData(id) {
const user = await fetchUser(id);
this.setState({ user });
}
render() {
const { id } = this.props;
const { user } = this.state;
if (user === null) {
return <p>Loading profile...</p>;
}
return (
<>
<h2>{user.name}</h2>
<ProfileTimeline id={id} />
</>
);
}
}
class ProfileTimeline extends React.Component {
state = {
posts: null,
};
componentDidMount() {
this.fetchData(this.props.id);
}
componentDidUpdate(prevProps) {
if (prevProps.id !== this.props.id) {
this.fetchData(this.props.id);
}
}
async fetchData(id) {
const posts = await fetchPosts(id);
this.setState({ posts });
}
render() {
const { posts } = this.state;
if (posts === null) {
return <h3>Loading posts...</h3>;
}
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
}
Try it on CodeSandbox
This code is deceptively easy to read.
Unfortunately, neither using a class nor the async
/ await
syntax helped us solve this problem.
This version suffers from exactly the same race conditions, for the same reasons.
The Problem
React components have their own ¡°lifecycle¡±.
They may receive props or update state at any point in time.
However, each asynchronous request also has its own ¡°lifecycle¡±.
It starts when we kick it off, and finishes when we get a response.
The difficulty we're experiencing is ¡°synchronizing¡± several processes in time that affect each other.
This is hard to think about.
Solving Race Conditions with Suspense
Let's rewrite this example again, but using Suspense only:
const initialResource = fetchProfileData(0);
function App() {
const [resource, setResource] = useState(initialResource);
return (
<>
<button onClick={() => {
const nextUserId = getNextId(resource.userId);
setResource(fetchProfileData(nextUserId));
}}>
Next
</button>
<ProfilePage resource={resource} />
</>
);
}
function ProfilePage({ resource }) {
return (
<Suspense fallback={<h2>Loading profile...</h2>}>
<ProfileDetails resource={resource} />
<Suspense fallback={<h2>Loading posts...</h2>}>
<ProfileTimeline resource={resource} />
</Suspense>
</Suspense>
);
}
function ProfileDetails({ resource }) {
const user = resource.user.read();
return <h2>{user.name}</h2>;
}
function ProfileTimeline({ resource }) {
const posts = resource.posts.read();
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
Try it on CodeSandbox
In the previous Suspense example, we only had one resource
, so we held it in a top-level variable.
Now that we have multiple resources, we moved it to the <App>
's component state:
const initialResource = fetchProfileData(0);
function App() {
const [resource, setResource] = useState(initialResource);
When we click ¡°Next¡±, the <App>
component kicks off a request for the next profile, and passes that object down to the <ProfilePage>
component:
<>
<button onClick={() => {
const nextUserId = getNextId(resource.userId);
setResource(fetchProfileData(nextUserId)); }}>
Next
</button>
<ProfilePage resource={resource} /> </>
Again, notice that we're not waiting for the response to set the state.
It's the other way around: we set the state (and start rendering) immediately after kicking off a request.
As soon as we have more data, React ¡°fills in¡± the content inside <Suspense>
components.
This code is very readable, but unlike the examples earlier, the Suspense version doesn't suffer from race conditions.
You might be wondering why.
The answer is that in the Suspense version, we don't have to think about time as much in our code.
Our original code with race conditions needed to set the state at the right moment later, or otherwise it would be wrong.
But with Suspense, we set the state immediately ¡ª so it's harder to mess it up.
Handling Errors
When we write code with Promises, we might use catch()
to handle errors.
How does this work with Suspense, given that we don't wait for Promises to start rendering?
With Suspense, handling fetching errors works the same way as handling rendering errors ¡ª you can render an error boundary anywhere to ¡°catch¡± errors in components below.
First, we'll define an error boundary component to use across our project:
// Error boundaries currently have to be classes.
class ErrorBoundary extends React.Component {
state = { hasError: false, error: null };
static getDerivedStateFromError(error) {
return {
hasError: true,
error
};
}
render() {
if (this.state.hasError) {
return this.props.fallback;
}
return this.props.children;
}
}
And then we can put it anywhere in the tree to catch errors:
function ProfilePage() {
return (
<Suspense fallback={<h2>Loading profile...</h2>}>
<ProfileDetails />
<ErrorBoundary fallback={<h3>Could not fetch posts.</h3>}> <Suspense fallback={<h2>Loading posts...</h2>}>
<ProfileTimeline />
</Suspense>
</ErrorBoundary> </Suspense>
);
}
Try it on CodeSandbox
It would catch both rendering errors and errors from Suspense data fetching.
We can have as many error boundaries as we like but it's best to be intentional about their placement.
Next Steps
We've now covered the basics of Suspense for Data Fetching! Importantly, we now better understand why Suspense works this way, and how it fits into the data fetching space.
Suspense answers some questions, but it also poses new questions of its own:
- If some component ¡°suspends¡±, does the app freeze? How to avoid this?
- What if we want to show a spinner in a different place than ¡°above¡± the component in a tree?
- If we intentionally want to show an inconsistent UI for a small period of time, can we do that?
- Instead of showing a spinner, can we add a visual effect like ¡°greying out¡± the current screen?
- Why does our last Suspense example log a warning when clicking the ¡°Next¡± button?
To answer these questions, we will refer to the next section on Concurrent UI Patterns.
Concurrent UI Patterns (Experimental)
Caution:
This page describes experimental features that are not yet available in a stable release.
Don't rely on experimental builds of React in production apps.
These features may change significantly and without a warning before they become a part of React.
This documentation is aimed at early adopters and people who are curious.
If you're new to React, don't worry about these features ¡ª you don't need to learn them right now.
For example, if you're looking for a data fetching tutorial that works today, read this article instead.
Usually, when we update the state, we expect to see changes on the screen immediately.
This makes sense because we want to keep our app responsive to user input.
However, there are cases where we might prefer to defer an update from appearing on the screen.
For example, if we switch from one page to another, and none of the code or data for the next screen has loaded yet, it might be frustrating to immediately see a blank page with a loading indicator.
We might prefer to stay longer on the previous screen.
Implementing this pattern has historically been difficult in React.
Concurrent Mode offers a new set of tools to do that.
-
Transitions
- Wrapping setState in a Transition
- Adding a Pending Indicator
- Reviewing the Changes
- Where Does the Update Happen?
- Transitions Are Everywhere
- Baking Transitions Into the Design System
-
The Three Steps
- Default: Receded ¡ú Skeleton ¡ú Complete
- Preferred: Pending ¡ú Skeleton ¡ú Complete
- Wrap Lazy Features in
<Suspense>
- Suspense Reveal ¡°Train¡±
- Delaying a Pending Indicator
- Recap
-
Other Patterns
- Splitting High and Low Priority State
- Deferring a Value
- SuspenseList
- Next Steps
Transitions
Let's revisit this demo from the previous page about Suspense for Data Fetching.
When we click the ¡°Next¡± button to switch the active profile, the existing page data immediately disappears, and we see the loading indicator for the whole page again.
We can call this an ¡°undesirable¡± loading state.
It would be nice if we could ¡°skip¡± it and wait for some content to load before transitioning to the new screen.
React offers a new built-in useTransition()
Hook to help with this.
We can use it in three steps.
First, we'll make sure that we're actually using Concurrent Mode.
We'll talk more about adopting Concurrent Mode later, but for now it's sufficient to know that we need to use ReactDOM.createRoot()
rather than ReactDOM.render()
for this feature to work:
const rootElement = document.getElementById("root");
// Opt into Concurrent Mode
ReactDOM.createRoot(rootElement).render(<App />);
Next, we'll add an import for the useTransition
Hook from React:
import React, { useState, useTransition, Suspense } from "react";
Finally, we'll use it inside the App
component:
function App() {
const [resource, setResource] = useState(initialResource);
const [startTransition, isPending] = useTransition({ timeoutMs: 3000 }); // ...
By itself, this code doesn't do anything yet. We will need to use this Hook's return values to set up our state transition.
There are two values returned from useTransition
:
-
startTransition
is a function.
We'll use it to tell React which state update we want to defer.
-
isPending
is a boolean.
It's React telling us whether that transition is ongoing at the moment.
We will use them right below.
Note we passed a configuration object to useTransition
.
Its timeoutMs
property specifies how long we're willing to wait for the transition to finish.
By passing {timeoutMs: 3000}
, we say ¡°If the next profile takes more than 3 seconds to load, show the big spinner ¡ª but before that timeout it's okay to keep showing the previous screen¡±.
Wrapping setState in a Transition
Our ¡°Next¡± button click handler sets the state that switches the current profile in the state:
<button
onClick={() => {
const nextUserId = getNextId(resource.userId);
setResource(fetchProfileData(nextUserId)); }}
>
We'll wrap that state update into startTransition
.
That's how we tell React we don't mind React delaying that state update if it leads to an undesirable loading state:
<button
onClick={() => {
startTransition(() => { const nextUserId = getNextId(resource.userId);
setResource(fetchProfileData(nextUserId));
}); }}
>
Try it on CodeSandbox
Press ¡°Next¡± a few times.
Notice it already feels very different.
Instead of immediately seeing an empty screen on click, we now keep seeing the previous page for a while. When the data has loaded, React transitions us to the new screen.
If we make our API responses take 5 seconds, we can confirm that now React ¡°gives up¡± and transitions anyway to the next screen after 3 seconds.
This is because we passed {timeoutMs: 3000}
to useTransition()
.
For example, if we passed {timeoutMs: 60000}
instead, it would wait a whole minute.
Adding a Pending Indicator
There's still something that feels broken about our last example.
Sure, it's nice not to see a ¡°bad¡± loading state.
But having no indication of progress at all feels even worse! When we click ¡°Next¡±, nothing happens and it feels like the app is broken.
Our useTransition()
call returns two values: startTransition
and isPending
.
const [startTransition, isPending] = useTransition({ timeoutMs: 3000 });
We've already used startTransition
to wrap the state update.
Now we're going to use isPending
too.
React gives this boolean to us so we can tell whether we're currently waiting for this transition to finish.
We'll use it to indicate that something is happening:
return (
<>
<button
disabled={isPending} onClick={() => {
startTransition(() => {
const nextUserId = getNextId(resource.userId);
setResource(fetchProfileData(nextUserId));
});
}}
>
Next
</button>
{isPending ? " Loading..." : null} <ProfilePage resource={resource} />
</>
);
Try it on CodeSandbox
Now, this feels a lot better! When we click Next, it gets disabled because clicking it multiple times doesn't make sense.
And the new ¡°Loading¡¡± tells the user that the app didn't freeze.
Reviewing the Changes
Let's take another look at all the changes we've made since the original example:
function App() {
const [resource, setResource] = useState(initialResource);
const [startTransition, isPending] = useTransition({ timeoutMs: 3000 }); return (
<>
<button
disabled={isPending} onClick={() => {
startTransition(() => { const nextUserId = getNextId(resource.userId);
setResource(fetchProfileData(nextUserId));
}); }}
>
Next
</button>
{isPending ? " Loading..." : null} <ProfilePage resource={resource} />
</>
);
}
Try it on CodeSandbox
It took us only seven lines of code to add this transition:
- We've imported the
useTransition
Hook and used it in the component that updates the state.
- We've passed
{timeoutMs: 3000}
to stay on the previous screen for at most 3 seconds.
- We've wrapped our state update into
startTransition
to tell React it's okay to delay it.
- We're using
isPending
to communicate the state transition progress to the user and to disable the button.
As a result, clicking ¡°Next¡± doesn't perform an immediate state transition to an ¡°undesirable¡± loading state, but instead stays on the previous screen and communicates progress there.
Where Does the Update Happen?
This wasn't very difficult to implement.
However, if you start thinking about how this could possibly work, it might become a little mindbending.
If we set the state, how come we don't see the result right away? Where is the next <ProfilePage>
rendering?
Clearly, both ¡°versions¡± of <ProfilePage>
exist at the same time.
We know the old one exists because we see it on the screen and even display a progress indicator on it.
And we know the new version also exists somewhere, because it's the one that we're waiting for!
But how can two versions of the same component exist at the same time?
This gets at the root of what Concurrent Mode is.
We've previously said it's a bit like React working on state update on a ¡°branch¡±.
Another way we can conceptualize is that wrapping a state update in startTransition
begins rendering it ¡°in a different universe¡±, much like in science fiction movies.
We don't ¡°see¡± that universe directly ¡ª but we can get a signal from it that tells us something is happening (isPending
).
When the update is ready, our ¡°universes¡± merge back together, and we see the result on the screen!
Play a bit more with the demo, and try to imagine it happening.
Of course, two versions of the tree rendering at the same time is an illusion, just like the idea that all programs run on your computer at the same time is an illusion.
An operating system switches between different applications very fast.
Similarly, React can switch between the version of the tree you see on the screen and the version that it's ¡°preparing¡± to show next.
An API like useTransition
lets you focus on the desired user experience, and not think about the mechanics of how it's implemented.
Still, it can be a helpful metaphor to imagine that updates wrapped in startTransition
happen ¡°on a branch¡± or ¡°in a different world¡±.
Transitions Are Everywhere
As we learned from the Suspense walkthrough, any component can ¡°suspend¡± any time if some data it needs is not ready yet.
We can strategically place <Suspense>
boundaries in different parts of the tree to handle this, but it won't always be enough.
Let's get back to our first Suspense demo where there was just one profile.
Currently, it fetches the data only once.
We'll add a ¡°Refresh¡± button to check for server updates.
Our first attempt might look like this:
const initialResource = fetchUserAndPosts();
function ProfilePage() {
const [resource, setResource] = useState(initialResource);
function handleRefreshClick() { setResource(fetchUserAndPosts()); }
return (
<Suspense fallback={<h2>Loading profile...</h2>}>
<ProfileDetails resource={resource} />
<button onClick={handleRefreshClick}> Refresh </button> <Suspense fallback={<h2>Loading posts...</h2>}>
<ProfileTimeline resource={resource} />
</Suspense>
</Suspense>
);
}
Try it on CodeSandbox
In this example, we start data fetching at the load and every time you press ¡°Refresh¡±.
We put the result of calling fetchUserAndPosts()
into state so that components below can start reading the new data from the request we just kicked off.
We can see in this example that pressing ¡°Refresh¡± works.
The <ProfileDetails>
and <ProfileTimeline>
components receive a new resource
prop that represents the fresh data, they ¡°suspend¡± because we don't have a response yet, and we see the fallbacks.
When the response loads, we can see the updated posts (our fake API adds them every 3 seconds).
However, the experience feels really jarring.
We were browsing a page, but it got replaced by a loading state right as we were interacting with it.
It's disorienting.
Just like before, to avoid showing an undesirable loading state, we can wrap the state update in a transition:
function ProfilePage() {
const [startTransition, isPending] = useTransition({ // Wait 10 seconds before fallback timeoutMs: 10000 }); const [resource, setResource] = useState(initialResource);
function handleRefreshClick() {
startTransition(() => { setResource(fetchProfileData()); }); }
return (
<Suspense fallback={<h2>Loading profile...</h2>}>
<ProfileDetails resource={resource} />
<button
onClick={handleRefreshClick}
disabled={isPending}
>
{isPending ? "Refreshing..." : "Refresh"} </button>
<Suspense fallback={<h2>Loading posts...</h2>}>
<ProfileTimeline resource={resource} />
</Suspense>
</Suspense>
);
}
Try it on CodeSandbox
This feels a lot better! Clicking ¡°Refresh¡± doesn't pull us away from the page we're browsing anymore.
We see something is loading ¡°inline¡±, and when the data is ready, it's displayed.
Baking Transitions Into the Design System
We can now see that the need for useTransition
is very common.
Pretty much any button click or interaction that can lead to a component suspending needs to be wrapped in useTransition
to avoid accidentally hiding something the user is interacting with.
This can lead to a lot of repetitive code across components.
This is why we generally recommend to bake useTransition
into the design system components of your app.
For example, we can extract the transition logic into our own <Button>
component:
function Button({ children, onClick }) {
const [startTransition, isPending] = useTransition({
timeoutMs: 10000
});
function handleClick() {
startTransition(() => { onClick(); }); }
const spinner = (
// ...
);
return (
<>
<button
onClick={handleClick}
disabled={isPending} >
{children}
</button>
{isPending ? spinner : null} </>
);
}
Try it on CodeSandbox
Note that the button doesn't care what state we're updating.
It's wrapping any state updates that happen during its onClick
handler into a transition.
Now that our <Button>
takes care of setting up the transition, the <ProfilePage>
component doesn't need to set up its own:
function ProfilePage() {
const [resource, setResource] = useState(initialResource);
function handleRefreshClick() { setResource(fetchProfileData()); }
return (
<Suspense fallback={<h2>Loading profile...</h2>}>
<ProfileDetails resource={resource} />
<Button onClick={handleRefreshClick}> Refresh </Button> <Suspense fallback={<h2>Loading posts...</h2>}>
<ProfileTimeline resource={resource} />
</Suspense>
</Suspense>
);
}
Try it on CodeSandbox
When a button gets clicked, it starts a transition and calls props.onClick()
inside of it ¡ª which triggers handleRefreshClick
in the <ProfilePage>
component.
We start fetching the fresh data, but it doesn't trigger a fallback because we're inside a transition, and the 10 second timeout specified in the useTransition
call hasn't passed yet.
While a transition is pending, the button displays an inline loading indicator.
We can see now how Concurrent Mode helps us achieve a good user experience without sacrificing isolation and modularity of components.
React coordinates the transition.
The Three Steps
By now we have discussed all of the different visual states that an update may go through.
In this section, we will give them names and talk about the progression between them.
At the very end, we have the Complete state.
That's where we want to eventually get to.
It represents the moment when the next screen is fully rendered and isn't loading more data.
But before our screen can be Complete, we might need to load some data or code.
When we're on the next screen, but some parts of it are still loading, we call that a Skeleton state.
Finally, there are two primary ways that lead us to the Skeleton state.
We will illustrate the difference between them with a concrete example.
Default: Receded ¡ú Skeleton ¡ú Complete
Open this example and click ¡°Open Profile¡±.
You will see several visual states one by one:
-
Receded: For a second, you will see the
<h2>Loading the app...</h2>
fallback.
-
Skeleton: You will see the
<ProfilePage>
component with <h3>Loading posts...</h3>
inside.
-
Complete: You will see the
<ProfilePage>
component with no fallbacks inside.
Everything was fetched.
How do we separate the Receded and the Skeleton states? The difference between them is that the Receded state feels like ¡°taking a step back¡± to the user, while the Skeleton state feels like ¡°taking a step forward¡± in our progress to show more content.
In this example, we started our journey on the <HomePage>
:
<Suspense fallback={...}>
{/* previous screen */}
<HomePage />
</Suspense>
After the click, React started rendering the next screen:
<Suspense fallback={...}>
{/* next screen */}
<ProfilePage>
<ProfileDetails />
<Suspense fallback={...}>
<ProfileTimeline />
</Suspense>
</ProfilePage>
</Suspense>
Both <ProfileDetails>
and <ProfileTimeline>
need data to render, so they suspend:
<Suspense fallback={...}>
{/* next screen */}
<ProfilePage>
<ProfileDetails /> {/* suspends! */} <Suspense fallback={<h3>Loading posts...</h3>}>
<ProfileTimeline /> {/* suspends! */} </Suspense>
</ProfilePage>
</Suspense>
When a component suspends, React needs to show the closest fallback.
But the closest fallback to <ProfileDetails>
is at the top level:
<Suspense fallback={
// We see this fallback now because of <ProfileDetails> <h2>Loading the app...</h2>}>
{/* next screen */}
<ProfilePage>
<ProfileDetails /> {/* suspends! */} <Suspense fallback={...}>
<ProfileTimeline />
</Suspense>
</ProfilePage>
</Suspense>
This is why when we click the button, it feels like we've ¡°taken a step back¡±.
The <Suspense>
boundary which was previously showing useful content (<HomePage />
) had to ¡°recede¡± to showing the fallback (<h2>Loading the app...</h2>
).
We call that a Receded state.
As we load more data, React will retry rendering, and <ProfileDetails>
can render successfully.
Finally, we're in the Skeleton state.
We see the new page with missing parts:
<Suspense fallback={...}>
{/* next screen */}
<ProfilePage>
<ProfileDetails />
<Suspense fallback={
// We see this fallback now because of <ProfileTimeline> <h3>Loading posts...</h3> }>
<ProfileTimeline /> {/* suspends! */} </Suspense>
</ProfilePage>
</Suspense>
Eventually, they load too, and we get to the Complete state.
This scenario (Receded ¡ú Skeleton ¡ú Complete) is the default one.
However, the Receded state is not very pleasant because it ¡°hides¡± existing information.
This is why React lets us opt into a different sequence (Pending ¡ú Skeleton ¡ú Complete) with useTransition
.
Preferred: Pending ¡ú Skeleton ¡ú Complete
When we useTransition
, React will let us ¡°stay¡± on the previous screen ¡ª and show a progress indicator there.
We call that a Pending state.
It feels much better than the Receded state because none of our existing content disappears, and the page stays interactive.
You can compare these two examples to feel the difference:
- Default: Receded ¡ú Skeleton ¡ú Complete
- Preferred: Pending ¡ú Skeleton ¡ú Complete
The only difference between these two examples is that the first uses regular <button>
s, but the second one uses our custom <Button>
component with useTransition
.
Wrap Lazy Features in <Suspense>
Open this example.
When you press a button, you'll see the Pending state for a second before moving on.
This transition feels nice and fluid.
We will now add a brand new feature to the profile page ¡ª a list of fun facts about a person:
function ProfilePage({ resource }) {
return (
<>
<ProfileDetails resource={resource} />
<Suspense fallback={<h3>Loading posts...</h3>}>
<ProfileTimeline resource={resource} />
</Suspense>
<ProfileTrivia resource={resource} /> </>
);
}
function ProfileTrivia({ resource }) { const trivia = resource.trivia.read(); return ( <> <h3>Fun Facts</h3> <ul> {trivia.map(fact => ( <li key={fact.id}>{fact.text}</li> ))} </ul> </> );}
Try it on CodeSandbox
If you press ¡°Open Profile¡± now, you can tell something is wrong.
It takes a whole seven seconds to make the transition now! This is because our trivia API is too slow.
Let's say we can't make the API faster.
How can we improve the user experience with this constraint?
If we don't want to stay in the Pending state for too long, our first instinct might be to set timeoutMs
in useTransition
to something smaller, like 3000
.
You can try this here.
This lets us escape the prolonged Pending state, but we still don't have anything useful to show!
There is a simpler way to solve this.
Instead of making the transition shorter, we can ¡°disconnect¡± the slow component from the transition by wrapping it into <Suspense>
:
function ProfilePage({ resource }) {
return (
<>
<ProfileDetails resource={resource} />
<Suspense fallback={<h3>Loading posts...</h3>}>
<ProfileTimeline resource={resource} />
</Suspense>
<Suspense fallback={<h3>Loading fun facts...</h3>}> <ProfileTrivia resource={resource} />
</Suspense> </>
);
}
Try it on CodeSandbox
This reveals an important insight.
React always prefers to go to the Skeleton state as soon as possible.
Even if we use transitions with long timeouts everywhere, React will not stay in the Pending state for longer than necessary to avoid the Receded state.
If some feature isn't a vital part of the next screen, wrap it in <Suspense>
and let it load lazily. This ensures we can show the rest of the content as soon as possible.
Conversely, if a screen is not worth showing without some component, such as <ProfileDetails>
in our example, do not wrap it in <Suspense>
.
Then the transitions will ¡°wait¡± for it to be ready.
Suspense Reveal ¡°Train¡±
When we're already on the next screen, sometimes the data needed to ¡°unlock¡± different <Suspense>
boundaries arrives in quick succession.
For example, two different responses might arrive after 1000ms and 1050ms, respectively.
If you've already waited for a second, waiting another 50ms is not going to be perceptible.
This is why React reveals <Suspense>
boundaries on a schedule, like a ¡°train¡± that arrives periodically.
This trades a small delay for reducing the layout thrashing and the number of visual changes presented to the user.
You can see a demo of this here.
The ¡°posts¡± and ¡°fun facts¡± responses come within 100ms of each other.
But React coalesces them and ¡°reveals¡± their Suspense boundaries together.
Delaying a Pending Indicator
Our Button
component will immediately show the Pending state indicator on click:
function Button({ children, onClick }) {
const [startTransition, isPending] = useTransition({ timeoutMs: 10000
});
// ...
return (
<>
<button onClick={handleClick} disabled={isPending}>
{children}
</button>
{isPending ? spinner : null} </>
);
}
Try it on CodeSandbox
This signals to the user that some work is happening.
However, if the transition is relatively short (less than 500ms), it might be too distracting and make the transition itself feel slower.
One possible solution to this is to delay the spinner itself from displaying:
.DelayedSpinner {
animation: 0s linear 0.5s forwards makeVisible;
visibility: hidden;
}
@keyframes makeVisible {
to {
visibility: visible;
}
}
const spinner = (
<span className="DelayedSpinner"> {/* ...
*/} </span>);
return (
<>
<button onClick={handleClick}>{children}</button>
{isPending ? spinner : null} </>
);
Try it on CodeSandbox
With this change, even though we're in the Pending state, we don't display any indication to the user until 500ms has passed.
This may not seem like much of an improvement when the API responses are slow.
But compare how it feels before and after when the API call is fast.
Even though the rest of the code hasn't changed, suppressing a ¡°too fast¡± loading state improves the perceived performance by not calling attention to the delay.
Recap
The most important things we learned so far are:
- By default, our loading sequence is Receded ¡ú Skeleton ¡ú Complete.
- The Receded state doesn't feel very nice because it hides existing content.
- With
useTransition
, we can opt into showing a Pending state first instead.
This will keep us on the previous screen while the next screen is being prepared.
- If we don't want some component to delay the transition, we can wrap it in its own
<Suspense>
boundary.
- Instead of doing
useTransition
in every other component, we can build it into our design system.
Other Patterns
Transitions are probably the most common Concurrent Mode pattern you'll encounter, but there are a few more patterns you might find useful.
Splitting High and Low Priority State
When you design React components, it is usually best to find the ¡°minimal representation¡± of state.
For example, instead of keeping firstName
, lastName
, and fullName
in state, it's usually better keep only firstName
and lastName
, and then calculate fullName
during rendering.
This lets us avoid mistakes where we update one state but forget the other state.
However, in Concurrent Mode there are cases where you might want to ¡°duplicate¡± some data in different state variables.
Consider this tiny translation app:
const initialQuery = "Hello, world";
const initialResource = fetchTranslation(initialQuery);
function App() {
const [query, setQuery] = useState(initialQuery);
const [resource, setResource] = useState(initialResource);
function handleChange(e) {
const value = e.target.value;
setQuery(value);
setResource(fetchTranslation(value));
}
return (
<>
<input
value={query}
onChange={handleChange}
/>
<Suspense fallback={<p>Loading...</p>}>
<Translation resource={resource} />
</Suspense>
</>
);
}
function Translation({ resource }) {
return (
<p>
<b>{resource.read()}</b>
</p>
);
}
Try it on CodeSandbox
Notice how when you type into the input, the <Translation>
component suspends, and we see the <p>Loading...</p>
fallback until we get fresh results.
This is not ideal.
It would be better if we could see the previous translation for a bit while we're fetching the next one.
In fact, if we open the console, we'll see a warning:
Warning: App triggered a user-blocking update that suspended.
The fix is to split the update into multiple parts: a user-blocking update to provide immediate feedback, and another update that triggers the bulk of the changes.
Refer to the documentation for useTransition to learn how to implement this pattern.
As we mentioned earlier, if some state update causes a component to suspend, that state update should be wrapped in a transition.
Let's add useTransition
to our component:
function App() {
const [query, setQuery] = useState(initialQuery);
const [resource, setResource] = useState(initialResource);
const [startTransition, isPending] = useTransition({ timeoutMs: 5000 });
function handleChange(e) {
const value = e.target.value;
startTransition(() => { setQuery(value);
setResource(fetchTranslation(value));
}); }
// ...
}
Try it on CodeSandbox
Try typing into the input now.
Something's wrong! The input is updating very slowly.
We've fixed the first problem (suspending outside of a transition).
But now because of the transition, our state doesn't update immediately, and it can't ¡°drive¡± a controlled input!
The answer to this problem is to split the state in two parts: a ¡°high priority¡± part that updates immediately, and a ¡°low priority¡± part that may wait for a transition.
In our example, we already have two state variables.
The input text is in query
, and we read the translation from resource
.
We want changes to the query
state to happen immediately, but changes to the resource
(i.e.
fetching a new translation) should trigger a transition.
So the correct fix is to put setQuery
(which doesn't suspend) outside the transition, but setResource
(which will suspend) inside of it.
function handleChange(e) {
const value = e.target.value;
// Outside the transition (urgent) setQuery(value);
startTransition(() => {
// Inside the transition (may be delayed)
setResource(fetchTranslation(value));
});
}
Try it on CodeSandbox
With this change, it works as expected.
We can type into the input immediately, and the translation later ¡°catches up¡± to what we have typed.
Deferring a Value
By default, React always renders a consistent UI.
Consider code like this:
<>
<ProfileDetails user={user} />
<ProfileTimeline user={user} />
</>
React guarantees that whenever we look at these components on the screen, they will reflect data from the same user
.
If a different user
is passed down because of a state update, you would see them changing together.
You can't ever record a screen and find a frame where they would show values from different user
s.
(If you ever run into a case like this, file a bug!)
This makes sense in the vast majority of situations.
Inconsistent UI is confusing and can mislead users.
(For example, it would be terrible if a messenger's Send button and the conversation picker pane ¡°disagreed¡± about which thread is currently selected.)
However, sometimes it might be helpful to intentionally introduce an inconsistency.
We could do it manually by ¡°splitting¡± the state like above, but React also offers a built-in Hook for this:
import { useDeferredValue } from 'react';
const deferredValue = useDeferredValue(value, {
timeoutMs: 5000
});
To demonstrate this feature, we'll use the profile switcher example.
Click the ¡°Next¡± button and notice how it takes 1 second to do a transition.
Let's say that fetching the user details is very fast and only takes 300 milliseconds.
Currently, we're waiting a whole second because we need both user details and posts to display a consistent profile page.
But what if we want to show the details faster?
If we're willing to sacrifice consistency, we could pass potentially stale data to the components that delay our transition.
That's what useDeferredValue()
lets us do:
function ProfilePage({ resource }) {
const deferredResource = useDeferredValue(resource, { timeoutMs: 1000 }); return (
<Suspense fallback={<h2>Loading profile...</h2>}>
<ProfileDetails resource={resource} />
<Suspense fallback={<h2>Loading posts...</h2>}>
<ProfileTimeline
resource={deferredResource} isStale={deferredResource !== resource} />
</Suspense>
</Suspense>
);
}
function ProfileTimeline({ isStale, resource }) {
const posts = resource.posts.read();
return (
<ul style={{ opacity: isStale ? 0.7 : 1 }}> {posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
Try it on CodeSandbox
The tradeoff we're making here is that <ProfileTimeline>
will be inconsistent with other components and potentially show an older item.
Click ¡°Next¡± a few times, and you'll notice it.
But thanks to that, we were able to cut down the transition time from 1000ms to 300ms.
Whether or not it's an appropriate tradeoff depends on the situation.
But it's a handy tool, especially when the content doesn't change noticeably between items, and the user might not even realize they were looking at a stale version for a second.
It's worth noting that useDeferredValue
is not only useful for data fetching.
It also helps when an expensive component tree causes an interaction (e.g.
typing in an input) to be sluggish.
Just like we can ¡°defer¡± a value that takes too long to fetch (and show its old value despite other components updating), we can do this with trees that take too long to render.
For example, consider a filterable list like this:
function App() {
const [text, setText] = useState("hello");
function handleChange(e) {
setText(e.target.value);
}
return (
<div className="App">
<label>
Type into the input:{" "}
<input value={text} onChange={handleChange} />
</label>
...
<MySlowList text={text} />
</div>
);
}
Try it on CodeSandbox
In this example, every item in <MySlowList>
has an artificial slowdown ¡ª each of them blocks the thread for a few milliseconds.
We'd never do this in a real app, but this helps us simulate what can happen in a deep component tree with no single obvious place to optimize.
We can see how typing in the input causes stutter.
Now let's add useDeferredValue
:
function App() {
const [text, setText] = useState("hello");
const deferredText = useDeferredValue(text, { timeoutMs: 5000 });
function handleChange(e) {
setText(e.target.value);
}
return (
<div className="App">
<label>
Type into the input:{" "}
<input value={text} onChange={handleChange} />
</label>
...
<MySlowList text={deferredText} /> </div>
);
}
Try it on CodeSandbox
Now typing has a lot less stutter ¡ª although we pay for this by showing the results with a lag.
How is this different from debouncing? Our example has a fixed artificial delay (3ms for every one of 80 items), so there is always a delay, no matter how fast our computer is.
However, the useDeferredValue
value only ¡°lags behind¡± if the rendering takes a while.
There is no minimal lag imposed by React.
With a more realistic workload, you can expect the lag to adjust to the user's device.
On fast machines, the lag would be smaller or non-existent, and on slow machines, it would be more noticeable.
In both cases, the app would remain responsive.
That's the advantage of this mechanism over debouncing or throttling, which always impose a minimal delay and can't avoid blocking the thread while rendering.
Even though there is an improvement in responsiveness, this example isn't as compelling yet because Concurrent Mode is missing some crucial optimizations for this use case.
Still, it is interesting to see that features like useDeferredValue
(or useTransition
) are useful regardless of whether we're waiting for network or for computational work to finish.
SuspenseList
<SuspenseList>
is the last pattern that's related to orchestrating loading states.
Consider this example:
function ProfilePage({ resource }) {
return (
<>
<ProfileDetails resource={resource} />
<Suspense fallback={<h3>Loading posts...</h3>}> <ProfileTimeline resource={resource} /> </Suspense> <Suspense fallback={<h3>Loading fun facts...</h3>}> <ProfileTrivia resource={resource} /> </Suspense> </>
);
}
Try it on CodeSandbox
The API call duration in this example is randomized.
If you keep refreshing it, you will notice that sometimes the posts arrive first, and sometimes the ¡°fun facts¡± arrive first.
This presents a problem.
If the response for fun facts arrives first, we'll see the fun facts below the <h3>Loading posts...</h3>
fallback for posts.
We might start reading them, but then the posts response will come back, and shift all the facts down.
This is jarring.
One way we could fix it is by putting them both in a single boundary:
<Suspense fallback={<h3>Loading posts and fun facts...</h3>}>
<ProfileTimeline resource={resource} />
<ProfileTrivia resource={resource} />
</Suspense>
Try it on CodeSandbox
The problem with this is that now we always wait for both of them to be fetched.
However, if it's the posts that came back first, there's no reason to delay showing them.
When fun facts load later, they won't shift the layout because they're already below the posts.
Other approaches to this, such as composing Promises in a special way, are increasingly difficult to pull off when the loading states are located in different components down the tree.
To solve this, we will import SuspenseList
:
import { SuspenseList } from 'react';
<SuspenseList>
coordinates the ¡°reveal order¡± of the closest <Suspense>
nodes below it:
function ProfilePage({ resource }) {
return (
<SuspenseList revealOrder="forwards"> <ProfileDetails resource={resource} />
<Suspense fallback={<h3>Loading posts...</h3>}>
<ProfileTimeline resource={resource} />
</Suspense>
<Suspense fallback={<h3>Loading fun facts...</h3>}>
<ProfileTrivia resource={resource} />
</Suspense>
</SuspenseList> );
}
Try it on CodeSandbox
The revealOrder="forwards"
option means that the closest <Suspense>
nodes inside this list will only ¡°reveal¡± their content in the order they appear in the tree ¡ª even if the data for them arrives in a different order.
<SuspenseList>
has other interesting modes: try changing "forwards"
to "backwards"
or "together"
and see what happens.
You can control how many loading states are visible at once with the tail
prop.
If we specify tail="collapsed"
, we'll see at most one fallback at a time.
You can play with it here.
Keep in mind that <SuspenseList>
is composable, like anything in React.
For example, you can create a grid by putting several <SuspenseList>
rows inside a <SuspenseList>
table.
Next Steps
Concurrent Mode offers a powerful UI programming model and a set of new composable primitives to help you orchestrate delightful user experiences.
It's a result of several years of research and development, but it's not finished.
In the section on adopting Concurrent Mode, we'll describe how you can try it and what you can expect.
Adopting Concurrent Mode (Experimental)
Caution:
This page describes experimental features that are not yet available in a stable release.
Don't rely on experimental builds of React in production apps.
These features may change significantly and without a warning before they become a part of React.
This documentation is aimed at early adopters and people who are curious.
If you're new to React, don't worry about these features ¡ª you don't need to learn them right now.
-
Installation
- Who Is This Experimental Release For?
- Enabling Concurrent Mode
-
What to Expect
- Migration Step: Blocking Mode
- Why So Many Modes?
- Feature Comparison
Installation
Concurrent Mode is only available in the experimental builds of React.
To install them, run:
npm install react@experimental react-dom@experimental
There are no semantic versioning guarantees for the experimental builds.
APIs may be added, changed, or removed with any @experimental
release.
Experimental releases will have frequent breaking changes.
You can try these builds on personal projects or in a branch, but we don't recommend running them in production.
At Facebook, we do run them in production, but that's because we're also there to fix bugs when something breaks.
You've been warned!
Who Is This Experimental Release For?
This release is primarily aimed at early adopters, library authors, and curious people.
We're using this code in production (and it works for us) but there are still some bugs, missing features, and gaps in the documentation.
We'd like to hear more about what breaks in Concurrent Mode so we can better prepare it for an official stable release in the future.
Enabling Concurrent Mode
Normally, when we add features to React, you can start using them immediately.
Fragments, Context, and even Hooks are examples of such features.
You can use them in new code without making any changes to the existing code.
Concurrent Mode is different.
It introduces semantic changes to how React works.
Otherwise, the new features enabled by it wouldn't be possible.
This is why they're grouped into a new ¡°mode¡± rather than released one by one in isolation.
You can't opt into Concurrent Mode on a per-subtree basis.
Instead, to opt in, you have to do it in the place where today you call ReactDOM.render()
.
This will enable Concurrent Mode for the whole <App />
tree:
import ReactDOM from 'react-dom';
// If you previously had:
//
// ReactDOM.render(<App />, document.getElementById('root'));
//
// You can opt into Concurrent Mode by writing:
ReactDOM.unstable_createRoot(
document.getElementById('root')
).render(<App />);
Note:
Concurrent Mode APIs such as createRoot
only exist in the experimental builds of React.
In Concurrent Mode, the lifecycle methods previously marked as ¡°unsafe¡± actually are unsafe, and lead to bugs even more than in today's React.
We don't recommend trying Concurrent Mode until your app is Strict Mode-compatible.
What to Expect
If you have a large existing app, or if your app depends on a lot of third-party packages, please don't expect that you can use the Concurrent Mode immediately.
For example, at Facebook we are using Concurrent Mode for the new website, but we're not planning to enable it on the old website. This is because our old website still uses unsafe lifecycle methods in the product code, incompatible third-party libraries, and patterns that don't work well with the Concurrent Mode.
In our experience, code that uses idiomatic React patterns and doesn't rely on external state management solutions is the easiest to get running in the Concurrent Mode.
We will describe common problems we've seen and the solutions to them separately in the coming weeks.
Migration Step: Blocking Mode
For older codebases, Concurrent Mode might be a step too far.
This is why we also provide a new ¡°Blocking Mode¡± in the experimental React builds.
You can try it by substituting createRoot
with createBlockingRoot
.
It only offers a small subset of the Concurrent Mode features, but it is closer to how React works today and can serve as a migration step.
To recap:
-
Legacy Mode:
ReactDOM.render(<App />, rootNode)
.
This is what React apps use today.
There are no plans to remove the legacy mode in the observable future ¡ª but it won't be able to support these new features.
-
Blocking Mode:
ReactDOM.createBlockingRoot(rootNode).render(<App />)
.
It is currently experimental.
It is intended as a first migration step for apps that want to get a subset of Concurrent Mode features.
-
Concurrent Mode:
ReactDOM.createRoot(rootNode).render(<App />)
.
It is currently experimental.
In the future, after it stabilizes, we intend to make it the default React mode.
This mode enables all the new features.
Why So Many Modes?
We think it is better to offer a gradual migration strategy than to make huge breaking changes ¡ª or to let React stagnate into irrelevance.
In practice, we expect that most apps using Legacy Mode today should be able to migrate at least to the Blocking Mode (if not Concurrent Mode).
This fragmentation can be annoying for libraries that aim to support all Modes in the short term.
However, gradually moving the ecosystem away from the Legacy Mode will also solve problems that affect major libraries in the React ecosystem, such as confusing Suspense behavior when reading layout and lack of consistent batching guarantees.
There's a number of bugs that can't be fixed in Legacy Mode without changing semantics, but don't exist in Blocking and Concurrent Modes.
You can think of the Blocking Mode as a ¡°gracefully degraded¡± version of the Concurrent Mode.
As a result, in longer term we should be able to converge and stop thinking about different Modes altogether. But for now, Modes are an important migration strategy.
They let everyone decide when a migration is worth it, and upgrade at their own pace.
Feature Comparison
|
Legacy Mode |
Blocking Mode |
Concurrent Mode |
String Refs |
|
** |
** |
Legacy Context |
|
** |
** |
findDOMNode |
|
** |
** |
Suspense |
|
|
|
SuspenseList |
|
|
|
Suspense SSR + Hydration |
|
|
|
Progressive Hydration |
|
|
|
Selective Hydration |
|
|
|
Cooperative Multitasking |
|
|
|
Automatic batching of multiple setStates |
* |
|
|
Priority-based Rendering |
|
|
|
Interruptible Prerendering |
|
|
|
useTransition |
|
|
|
useDeferredValue |
|
|
|
Suspense Reveal ¡°Train¡± |
|
|
|
*: Legacy mode has automatic batching in React-managed events but it's limited to one browser task.
Non-React events must opt-in using unstable_batchedUpdates
.
In Blocking Mode and Concurrent Mode, all setState
s are batched by default.
**: Warns in development.
Concurrent Mode API Reference (Experimental)
Caution:
This page describes experimental features that are not yet available in a stable release.
Don't rely on experimental builds of React in production apps.
These features may change significantly and without a warning before they become a part of React.
This documentation is aimed at early adopters and people who are curious.
If you're new to React, don't worry about these features ¡ª you don't need to learn them right now.
This page is an API reference for the React Concurrent Mode.
If you're looking for a guided introduction instead, check out Concurrent UI Patterns.
Note: This is a Community Preview and not the final stable version.
There will likely be future changes to these APIs.
Use at your own risk!
-
Enabling Concurrent Mode
createRoot
createBlockingRoot
-
Suspense
Suspense
SuspenseList
useTransition
useDeferredValue
Enabling Concurrent Mode
createRoot
ReactDOM.createRoot(rootNode).render(<App />);
Replaces ReactDOM.render(<App />, rootNode)
and enables Concurrent Mode.
For more information on Concurrent Mode, check out the Concurrent Mode documentation.
createBlockingRoot
ReactDOM.createBlockingRoot(rootNode).render(<App />)
Replaces ReactDOM.render(<App />, rootNode)
and enables Blocking Mode.
Opting into Concurrent Mode introduces semantic changes to how React works.
This means that you can't use Concurrent Mode in just a few components.
Because of this, some apps may not be able to migrate directly to Concurrent Mode.
Blocking Mode only contains a small subset of Concurrent Mode features and is intended as an intermediary migration step for apps that are unable to migrate directly.
Suspense API
Suspense
<Suspense fallback={<h2>Loading...</h2>}>
<ProfilePhoto />
<ProfileDetails />
</Suspense>
Suspense
lets your components ¡°wait¡± for something before they can render, showing a fallback while waiting.
In this example, ProfileDetails
is waiting for an asynchronous API call to fetch some data.
While we wait for ProfileDetails
and ProfilePhoto
, we will show the Loading...
fallback instead.
It is important to note that until all children inside <Suspense>
has loaded, we will continue to show the fallback.
Suspense
takes two props:
-
fallback takes a loading indicator.
The fallback is shown until all of the children of the
Suspense
component have finished rendering.
-
unstable_avoidThisFallback takes a boolean.
It tells React whether to ¡°skip¡± revealing this boundary during the initial load.
This API will likely be removed in a future release.
<SuspenseList>
<SuspenseList revealOrder="forwards">
<Suspense fallback={'Loading...'}>
<ProfilePicture id={1} />
</Suspense>
<Suspense fallback={'Loading...'}>
<ProfilePicture id={2} />
</Suspense>
<Suspense fallback={'Loading...'}>
<ProfilePicture id={3} />
</Suspense>
...
</SuspenseList>
SuspenseList
helps coordinate many components that can suspend by orchestrating the order in which these components are revealed to the user.
When multiple components need to fetch data, this data may arrive in an unpredictable order.
However, if you wrap these items in a SuspenseList
, React will not show an item in the list until previous items have been displayed (this behavior is adjustable).
SuspenseList
takes two props:
-
revealOrder (forwards, backwards, together) defines the order in which the
SuspenseList
children should be revealed.
-
together
reveals all of them when they're ready instead of one by one.
-
tail (collapsed, hidden) dictates how unloaded items in a
SuspenseList
is shown.
- By default,
SuspenseList
will show all fallbacks in the list.
-
collapsed
shows only the next fallback in the list.
-
hidden
doesn't show any unloaded items.
Note that SuspenseList
only operates on the closest Suspense
and SuspenseList
components below it.
It does not search for boundaries deeper than one level.
However, it is possible to nest multiple SuspenseList
components in each other to build grids.
useTransition
const SUSPENSE_CONFIG = { timeoutMs: 2000 };
const [startTransition, isPending] = useTransition(SUSPENSE_CONFIG);
useTransition
allows components to avoid undesirable loading states by waiting for content to load before transitioning to the next screen.
It also allows components to defer slower, data fetching updates until subsequent renders so that more crucial updates can be rendered immediately.
The useTransition
hook returns two values in an array.
-
startTransition
is a function that takes a callback.
We can use it to tell React which state we want to defer.
-
isPending
is a boolean.
It's React's way of informing us whether we're waiting for the transition to finish.
If some state update causes a component to suspend, that state update should be wrapped in a transition.
const SUSPENSE_CONFIG = { timeoutMs: 2000 };
function App() {
const [resource, setResource] = useState(initialResource);
const [startTransition, isPending] = useTransition(SUSPENSE_CONFIG);
return (
<>
<button
disabled={isPending}
onClick={() => {
startTransition(() => {
const nextUserId = getNextId(resource.userId);
setResource(fetchProfileData(nextUserId));
});
}}
>
Next
</button>
{isPending ? " Loading..." : null}
<Suspense fallback={<Spinner />}>
<ProfilePage resource={resource} />
</Suspense>
</>
);
}
In this code, we've wrapped our data fetching with startTransition
.
This allows us to start fetching the profile data right away, while deferring the render of the next profile page and its associated Spinner
for 2 seconds (the time shown in timeoutMs
).
The isPending
boolean lets React know that our component is transitioning, so we are able to let the user know this by showing some loading text on the previous profile page.
For an in-depth look at transitions, you can read Concurrent UI Patterns.
useTransition Config
const SUSPENSE_CONFIG = { timeoutMs: 2000 };
useTransition
accepts an optional Suspense Config with a timeoutMs
.
This timeout (in milliseconds) tells React how long to wait before showing the next state (the new Profile Page in the above example).
Note: We recommend that you share Suspense Config between different modules.
useDeferredValue
const deferredValue = useDeferredValue(value, { timeoutMs: 2000 });
Returns a deferred version of the value that may ¡°lag behind¡± it for at most timeoutMs
.
This is commonly used to keep the interface responsive when you have something that renders immediately based on user input and something that needs to wait for a data fetch.
A good example of this is a text input.
function App() {
const [text, setText] = useState("hello");
const deferredText = useDeferredValue(text, { timeoutMs: 2000 });
return (
<div className="App">
{/* Keep passing the current text to the input */}
<input value={text} onChange={handleChange} />
...
{/* But the list is allowed to "lag behind" when necessary */}
<MySlowList text={deferredText} />
</div>
);
}
This allows us to start showing the new text for the input
immediately, which allows the webpage to feel responsive.
Meanwhile, MySlowList
¡°lags behind¡± for up to 2 seconds according to the timeoutMs
before updating, allowing it to render with the current text in the background.
For an in-depth look at deferring values, you can read Concurrent UI Patterns.
useDeferredValue Config
const SUSPENSE_CONFIG = { timeoutMs: 2000 };
useDeferredValue
accepts an optional Suspense Config with a timeoutMs
.
This timeout (in milliseconds) tells React how long the deferred value is allowed to lag behind.
React will always try to use a shorter lag when network and device allows it.
How to Contribute
React is one of Facebook's first open source projects that is both under very active development and is also being used to ship code to everybody on facebook.com.
We're still working out the kinks to make contributing to this project as easy and transparent as possible, but we're not quite there yet.
Hopefully this document makes the process for contributing clear and answers some questions that you may have.
Code of Conduct
Facebook has adopted the Contributor Covenant as its Code of Conduct, and we expect project participants to adhere to it.
Please read the full text so that you can understand what actions will and will not be tolerated.
Open Development
All work on React happens directly on GitHub.
Both core team members and external contributors send pull requests which go through the same review process.
Semantic Versioning
React follows semantic versioning.
We release patch versions for critical bugfixes, minor versions for new features or non-essential changes, and major versions for any breaking changes.
When we make breaking changes, we also introduce deprecation warnings in a minor version so that our users learn about the upcoming changes and migrate their code in advance.
Learn more about our commitment to stability and incremental migration in our versioning policy.
Every significant change is documented in the changelog file.
Branch Organization
Submit all changes directly to the master branch
.
We don't use separate branches for development or for upcoming releases.
We do our best to keep master
in good shape, with all tests passing.
Code that lands in master
must be compatible with the latest stable release.
It may contain additional features, but no breaking changes.
We should be able to release a new minor version from the tip of master
at any time.
Feature Flags
To keep the master
branch in a releasable state, breaking changes and experimental features must be gated behind a feature flag.
Feature flags are defined in packages/shared/ReactFeatureFlags.js
.
Some builds of React may enable different sets of feature flags; for example, the React Native build may be configured differently than React DOM.
These flags are found in packages/shared/forks
.
Feature flags are statically typed by Flow, so you can run yarn flow
to confirm that you've updated all the necessary files.
React's build system will strip out disabled feature branches before publishing.
A continuous integration job runs on every commit to check for changes in bundle size.
You can use the change in size as a signal that a feature was gated correctly.
Bugs
Where to Find Known Issues
We are using GitHub Issues for our public bugs.
We keep a close eye on this and try to make it clear when we have an internal fix in progress.
Before filing a new task, try to make sure your problem doesn't already exist.
Reporting New Issues
The best way to get your bug fixed is to provide a reduced test case.
This JSFiddle template is a great starting point.
Security Bugs
Facebook has a bounty program for the safe disclosure of security bugs.
With that in mind, please do not file public issues; go through the process outlined on that page.
How to Get in Touch
- IRC: #reactjs on freenode
- Discussion forums
There is also an active community of React users on the Discord chat platform in case you need help with React.
Proposing a Change
If you intend to change the public API, or make any non-trivial changes to the implementation, we recommend filing an issue.
This lets us reach an agreement on your proposal before you put significant effort into it.
If you're only fixing a bug, it's fine to submit a pull request right away but we still recommend to file an issue detailing what you're fixing.
This is helpful in case we don't accept that specific fix but want to keep track of the issue.
Your First Pull Request
Working on your first Pull Request? You can learn how from this free video series:
How to Contribute to an Open Source Project on GitHub
To help you get your feet wet and get you familiar with our contribution process, we have a list of good first issues that contain bugs that have a relatively limited scope.
This is a great place to get started.
If you decide to fix an issue, please be sure to check the comment thread in case somebody is already working on a fix.
If nobody is working on it at the moment, please leave a comment stating that you intend to work on it so other people don't accidentally duplicate your effort.
If somebody claims an issue but doesn't follow up for more than two weeks, it's fine to take it over but you should still leave a comment.
Sending a Pull Request
The core team is monitoring for pull requests.
We will review your pull request and either merge it, request changes to it, or close it with an explanation.
For API changes we may need to fix our internal uses at Facebook.com, which could cause some delay.
We'll do our best to provide updates and feedback throughout the process.
Before submitting a pull request, please make sure the following is done:
- Fork the repository and create your branch from
master
.
- Run
yarn
in the repository root.
- If you've fixed a bug or added code that should be tested, add tests!
- Ensure the test suite passes (
yarn test
).
Tip: yarn test --watch TestName
is helpful in development.
- Run
yarn test --prod
to test in the production environment.
- If you need a debugger, run
yarn debug-test --watch TestName
, open chrome://inspect
, and press ¡°Inspect¡±.
- Format your code with prettier (
yarn prettier
).
- Make sure your code lints (
yarn lint
).
Tip: yarn linc
to only check changed files.
- Run the Flow typechecks (
yarn flow
).
- If you haven't already, complete the CLA.
Contributor License Agreement (CLA)
In order to accept your pull request, we need you to submit a CLA.
You only need to do this once, so if you've done this for another Facebook open source project, you're good to go.
If you are submitting a pull request for the first time, just let us know that you have completed the CLA and we can cross-check with your GitHub username.
Complete your CLA here.
Contribution Prerequisites
- You have Node installed at v8.0.0+ and Yarn at v1.2.0+.
- You have JDK installed.
- You have
gcc
installed or are comfortable installing a compiler if needed.
Some of our dependencies may require a compilation step.
On OS X, the Xcode Command Line Tools will cover this.
On Ubuntu, apt-get install build-essential
will install the required packages.
Similar commands should work on other Linux distros.
Windows will require some additional steps, see the node-gyp
installation instructions for details.
- You are familiar with Git.
Development Workflow
After cloning React, run yarn
to fetch its dependencies.
Then, you can run several commands:
-
yarn lint
checks the code style.
-
yarn linc
is like yarn lint
but faster because it only checks files that differ in your branch.
-
yarn test
runs the complete test suite.
-
yarn test --watch
runs an interactive test watcher.
-
yarn test --prod
runs tests in the production environment.
-
yarn test <pattern>
runs tests with matching filenames.
-
yarn debug-test
is just like yarn test
but with a debugger.
Open chrome://inspect
and press ¡°Inspect¡±.
-
yarn flow
runs the Flow typechecks.
-
yarn build
creates a build
folder with all the packages.
-
yarn build react/index,react-dom/index --type=UMD
creates UMD builds of just React and ReactDOM.
We recommend running yarn test
(or its variations above) to make sure you don't introduce any regressions as you work on your change.
However, it can be handy to try your build of React in a real project.
First, run yarn build
.
This will produce pre-built bundles in build
folder, as well as prepare npm packages inside build/packages
.
The easiest way to try your changes is to run yarn build react/index,react-dom/index --type=UMD
and then open fixtures/packaging/babel-standalone/dev.html
.
This file already uses react.development.js
from the build
folder so it will pick up your changes.
If you want to try your changes in your existing React project, you may copy build/dist/react.development.js
, build/dist/react-dom.development.js
, or any other build products into your app and use them instead of the stable version.
If your project uses React from npm, you may delete react
and react-dom
in its dependencies and use yarn link
to point them to your local build
folder.
Note that instead of --type=UMD
you'll want to pass --type=NODE
when building.
You'll also need to build the scheduler
package:
cd ~/path_to_your_react_clone/
yarn build react/index,react/jsx,react-dom/index,scheduler --type=NODE
cd build/node_modules/react
yarn link
cd build/node_modules/react-dom
yarn link
cd ~/path/to/your/project
yarn link react react-dom
Every time you run yarn build
in the React folder, the updated versions will appear in your project's node_modules
.
You can then rebuild your project to try your changes.
If some package is still missing (e.g.
maybe you use react-dom/server
in your project), you can always do a full build with yarn build
.
Note that running yarn build
without options takes a long time.
We still require that your pull request contains unit tests for any new functionality.
This way we can ensure that we don't break your code in the future.
Style Guide
We use an automatic code formatter called Prettier.
Run yarn prettier
after making any changes to the code.
Then, our linter will catch most issues that may exist in your code.
You can check the status of your code styling by simply running yarn linc
.
However, there are still some styles that the linter cannot pick up.
If you are unsure about something, looking at Airbnb's Style Guide will guide you in the right direction.
Request for Comments (RFC)
Many changes, including bug fixes and documentation improvements can be implemented and reviewed via the normal GitHub pull request workflow.
Some changes though are ¡°substantial¡±, and we ask that these be put through a bit of a design process and produce a consensus among the React core team.
The ¡°RFC¡± (request for comments) process is intended to provide a consistent and controlled path for new features to enter the project.
You can contribute by visiting the rfcs repository.
License
By contributing to React, you agree that your contributions will be licensed under its MIT license.
What Next?
Read the next section to learn how the codebase is organized.
Codebase Overview
This section will give you an overview of the React codebase organization, its conventions, and the implementation.
If you want to contribute to React we hope that this guide will help you feel more comfortable making changes.
We don't necessarily recommend any of these conventions in React apps.
Many of them exist for historical reasons and might change with time.
Top-Level Folders
After cloning the React repository, you will see a few top-level folders in it:
-
packages
contains metadata (such as package.json
) and the source code (src
subdirectory) for all packages in the React repository.
If your change is related to the code, the src
subdirectory of each package is where you'll spend most of your time.
-
fixtures
contains a few small React test applications for contributors.
-
build
is the build output of React.
It is not in the repository but it will appear in your React clone after you build it for the first time.
The documentation is hosted in a separate repository from React.
There are a few other top-level folders but they are mostly used for the tooling and you likely won't ever encounter them when contributing.
Colocated Tests
We don't have a top-level directory for unit tests.
Instead, we put them into a directory called __tests__
relative to the files that they test.
For example, a test for setInnerHTML.js
is located in __tests__/setInnerHTML-test.js
right next to it.
Warnings and Invariants
The React codebase uses console.error
to display warnings:
if (__DEV__) {
console.error('Something is wrong.');
}
Warnings are only enabled in development.
In production, they are completely stripped out.
If you need to forbid some code path from executing, use invariant
module instead:
var invariant = require('invariant');
invariant(
2 + 2 === 4,
'You shall not pass!'
);
The invariant is thrown when the invariant
condition is false
.
¡°Invariant¡± is just a way of saying ¡°this condition always holds true¡±.
You can think about it as making an assertion.
It is important to keep development and production behavior similar, so invariant
throws both in development and in production.
The error messages are automatically replaced with error codes in production to avoid negatively affecting the byte size.
Development and Production
You can use __DEV__
pseudo-global variable in the codebase to guard development-only blocks of code.
It is inlined during the compile step, and turns into process.env.NODE_ENV !== 'production'
checks in the CommonJS builds.
For standalone builds, it becomes true
in the unminified build, and gets completely stripped out with the if
blocks it guards in the minified build.
if (__DEV__) {
// This code will only run in development.
}
Flow
We recently started introducing Flow checks to the codebase.
Files marked with the @flow
annotation in the license header comment are being typechecked.
We accept pull requests adding Flow annotations to existing code.
Flow annotations look like this:
ReactRef.detachRefs = function(
instance: ReactInstance,
element: ReactElement | string | number | null | false,
): void {
// ...
}
When possible, new code should use Flow annotations.
You can run yarn flow
locally to check your code with Flow.
Multiple Packages
React is a monorepo.
Its repository contains multiple separate packages so that their changes can be coordinated together, and issues live in one place.
React Core
The ¡°core¡± of React includes all the top-level React
APIs, for example:
React.createElement()
React.Component
React.Children
React core only includes the APIs necessary to define components. It does not include the reconciliation algorithm or any platform-specific code.
It is used both by React DOM and React Native components.
The code for React core is located in packages/react
in the source tree.
It is available on npm as the react
package.
The corresponding standalone browser build is called react.js
, and it exports a global called React
.
Renderers
React was originally created for the DOM but it was later adapted to also support native platforms with React Native.
This introduced the concept of ¡°renderers¡± to React internals.
Renderers manage how a React tree turns into the underlying platform calls.
Renderers are also located in packages/
:
-
React DOM Renderer renders React components to the DOM.
It implements top-level
ReactDOM
APIs and is available as react-dom
npm package.
It can also be used as standalone browser bundle called react-dom.js
that exports a ReactDOM
global.
-
React Native Renderer renders React components to native views.
It is used internally by React Native.
-
React Test Renderer renders React components to JSON trees.
It is used by the Snapshot Testing feature of Jest and is available as react-test-renderer npm package.
The only other officially supported renderer is react-art
.
It used to be in a separate GitHub repository but we moved it into the main source tree for now.
Note:
Technically the react-native-renderer
is a very thin layer that teaches React to interact with React Native implementation.
The real platform-specific code managing the native views lives in the React Native repository together with its components.
Reconcilers
Even vastly different renderers like React DOM and React Native need to share a lot of logic.
In particular, the reconciliation algorithm should be as similar as possible so that declarative rendering, custom components, state, lifecycle methods, and refs work consistently across platforms.
To solve this, different renderers share some code between them.
We call this part of React a ¡°reconciler¡±.
When an update such as setState()
is scheduled, the reconciler calls render()
on components in the tree and mounts, updates, or unmounts them.
Reconcilers are not packaged separately because they currently have no public API.
Instead, they are exclusively used by renderers such as React DOM and React Native.
Stack Reconciler
The ¡°stack¡± reconciler is the implementation powering React 15 and earlier.
We have since stopped using it, but it is documented in detail in the next section.
Fiber Reconciler
The ¡°fiber¡± reconciler is a new effort aiming to resolve the problems inherent in the stack reconciler and fix a few long-standing issues.
It has been the default reconciler since React 16.
Its main goals are:
- Ability to split interruptible work in chunks.
- Ability to prioritize, rebase and reuse work in progress.
- Ability to yield back and forth between parents and children to support layout in React.
- Ability to return multiple elements from
render()
.
- Better support for error boundaries.
You can read more about React Fiber Architecture here and here.
While it has shipped with React 16, the async features are not enabled by default yet.
Its source code is located in packages/react-reconciler
.
Event System
React implements a layer over native events to smooth out cross-browser differences.
Its source code is located in packages/react-dom/src/events
.
What Next?
Read the next section to learn about the pre-React 16 implementation of reconciler in more detail.
We haven't documented the internals of the new reconciler yet.
Implementation Notes
This section is a collection of implementation notes for the stack reconciler.
It is very technical and assumes a strong understanding of React public API as well as how it's divided into core, renderers, and the reconciler.
If you're not very familiar with the React codebase, read the codebase overview first.
It also assumes an understanding of the differences between React components, their instances, and elements.
The stack reconciler was used in React 15 and earlier.
It is located at src/renderers/shared/stack/reconciler.
Video: Building React from Scratch
Paul O'Shannessy gave a talk about building React from scratch that largely inspired this document.
Both this document and his talk are simplifications of the real codebase so you might get a better understanding by getting familiar with both of them.
Overview
The reconciler itself doesn't have a public API.
Renderers like React DOM and React Native use it to efficiently update the user interface according to the React components written by the user.
Mounting as a Recursive Process
Let's consider the first time you mount a component:
ReactDOM.render(<App />, rootEl);
React DOM will pass <App />
along to the reconciler.
Remember that <App />
is a React element, that is, a description of what to render.
You can think about it as a plain object:
console.log(<App />);
// { type: App, props: {} }
The reconciler will check if App
is a class or a function.
If App
is a function, the reconciler will call App(props)
to get the rendered element.
If App
is a class, the reconciler will instantiate an App
with new App(props)
, call the componentWillMount()
lifecycle method, and then will call the render()
method to get the rendered element.
Either way, the reconciler will learn the element App
¡°rendered to¡±.
This process is recursive.
App
may render to a <Greeting />
, Greeting
may render to a <Button />
, and so on.
The reconciler will ¡°drill down¡± through user-defined components recursively as it learns what each component renders to.
You can imagine this process as a pseudocode:
function isClass(type) {
// React.Component subclasses have this flag
return (
Boolean(type.prototype) &&
Boolean(type.prototype.isReactComponent)
);
}
// This function takes a React element (e.g.
<App />)
// and returns a DOM or Native node representing the mounted tree.
function mount(element) {
var type = element.type;
var props = element.props;
// We will determine the rendered element
// by either running the type as function
// or creating an instance and calling render().
var renderedElement;
if (isClass(type)) {
// Component class
var publicInstance = new type(props);
// Set the props
publicInstance.props = props;
// Call the lifecycle if necessary
if (publicInstance.componentWillMount) {
publicInstance.componentWillMount();
}
// Get the rendered element by calling render()
renderedElement = publicInstance.render();
} else {
// Component function
renderedElement = type(props);
}
// This process is recursive because a component may
// return an element with a type of another component.
return mount(renderedElement);
// Note: this implementation is incomplete and recurses infinitely!
// It only handles elements like <App /> or <Button />.
// It doesn't handle elements like <div /> or <p /> yet.
}
var rootEl = document.getElementById('root');
var node = mount(<App />);
rootEl.appendChild(node);
Note:
This really is a pseudo-code.
It isn't similar to the real implementation.
It will also cause a stack overflow because we haven't discussed when to stop the recursion.
Let's recap a few key ideas in the example above:
- React elements are plain objects representing the component type (e.g.
App
) and the props.
- User-defined components (e.g.
App
) can be classes or functions but they all ¡°render to¡± elements.
- ¡°Mounting¡± is a recursive process that creates a DOM or Native tree given the top-level React element (e.g.
<App />
).
Mounting Host Elements
This process would be useless if we didn't render something to the screen as a result.
In addition to user-defined (¡°composite¡±) components, React elements may also represent platform-specific (¡°host¡±) components.
For example, Button
might return a <div />
from its render method.
If element's type
property is a string, we are dealing with a host element:
console.log(<div />);
// { type: 'div', props: {} }
There is no user-defined code associated with host elements.
When the reconciler encounters a host element, it lets the renderer take care of mounting it.
For example, React DOM would create a DOM node.
If the host element has children, the reconciler recursively mounts them following the same algorithm as above.
It doesn't matter whether children are host (like <div><hr /></div>
), composite (like <div><Button /></div>
), or both.
The DOM nodes produced by the child components will be appended to the parent DOM node, and recursively, the complete DOM structure will be assembled.
Note:
The reconciler itself is not tied to the DOM.
The exact result of mounting (sometimes called ¡°mount image¡± in the source code) depends on the renderer, and can be a DOM node (React DOM), a string (React DOM Server), or a number representing a native view (React Native).
If we were to extend the code to handle host elements, it would look like this:
function isClass(type) {
// React.Component subclasses have this flag
return (
Boolean(type.prototype) &&
Boolean(type.prototype.isReactComponent)
);
}
// This function only handles elements with a composite type.
// For example, it handles <App /> and <Button />, but not a <div />.
function mountComposite(element) {
var type = element.type;
var props = element.props;
var renderedElement;
if (isClass(type)) {
// Component class
var publicInstance = new type(props);
// Set the props
publicInstance.props = props;
// Call the lifecycle if necessary
if (publicInstance.componentWillMount) {
publicInstance.componentWillMount();
}
renderedElement = publicInstance.render();
} else if (typeof type === 'function') {
// Component function
renderedElement = type(props);
}
// This is recursive but we'll eventually reach the bottom of recursion when
// the element is host (e.g.
<div />) rather than composite (e.g.
<App />):
return mount(renderedElement);
}
// This function only handles elements with a host type.
// For example, it handles <div /> and <p /> but not an <App />.
function mountHost(element) {
var type = element.type;
var props = element.props;
var children = props.children || [];
if (!Array.isArray(children)) {
children = [children];
}
children = children.filter(Boolean);
// This block of code shouldn't be in the reconciler.
// Different renderers might initialize nodes differently.
// For example, React Native would create iOS or Android views.
var node = document.createElement(type);
Object.keys(props).forEach(propName => {
if (propName !== 'children') {
node.setAttribute(propName, props[propName]);
}
});
// Mount the children
children.forEach(childElement => {
// Children may be host (e.g.
<div />) or composite (e.g.
<Button />).
// We will also mount them recursively:
var childNode = mount(childElement);
// This line of code is also renderer-specific.
// It would be different depending on the renderer:
node.appendChild(childNode);
});
// Return the DOM node as mount result.
// This is where the recursion ends.
return node;
}
function mount(element) {
var type = element.type;
if (typeof type === 'function') {
// User-defined components
return mountComposite(element);
} else if (typeof type === 'string') {
// Platform-specific components
return mountHost(element);
}
}
var rootEl = document.getElementById('root');
var node = mount(<App />);
rootEl.appendChild(node);
This is working but still far from how the reconciler is really implemented.
The key missing ingredient is support for updates.
Introducing Internal Instances
The key feature of React is that you can re-render everything, and it won't recreate the DOM or reset the state:
ReactDOM.render(<App />, rootEl);
// Should reuse the existing DOM:
ReactDOM.render(<App />, rootEl);
However, our implementation above only knows how to mount the initial tree.
It can't perform updates on it because it doesn't store all the necessary information, such as all the publicInstance
s, or which DOM node
s correspond to which components.
The stack reconciler codebase solves this by making the mount()
function a method and putting it on a class.
There are drawbacks to this approach, and we are going in the opposite direction in the ongoing rewrite of the reconciler.
Nevertheless this is how it works now.
Instead of separate mountHost
and mountComposite
functions, we will create two classes: DOMComponent
and CompositeComponent
.
Both classes have a constructor accepting the element
, as well as a mount()
method returning the mounted node.
We will replace a top-level mount()
function with a factory that instantiates the correct class:
function instantiateComponent(element) {
var type = element.type;
if (typeof type === 'function') {
// User-defined components
return new CompositeComponent(element);
} else if (typeof type === 'string') {
// Platform-specific components
return new DOMComponent(element);
}
}
First, let's consider the implementation of CompositeComponent
:
class CompositeComponent {
constructor(element) {
this.currentElement = element;
this.renderedComponent = null;
this.publicInstance = null;
}
getPublicInstance() {
// For composite components, expose the class instance.
return this.publicInstance;
}
mount() {
var element = this.currentElement;
var type = element.type;
var props = element.props;
var publicInstance;
var renderedElement;
if (isClass(type)) {
// Component class
publicInstance = new type(props);
// Set the props
publicInstance.props = props;
// Call the lifecycle if necessary
if (publicInstance.componentWillMount) {
publicInstance.componentWillMount();
}
renderedElement = publicInstance.render();
} else if (typeof type === 'function') {
// Component function
publicInstance = null;
renderedElement = type(props);
}
// Save the public instance
this.publicInstance = publicInstance;
// Instantiate the child internal instance according to the element.
// It would be a DOMComponent for <div /> or <p />,
// and a CompositeComponent for <App /> or <Button />:
var renderedComponent = instantiateComponent(renderedElement);
this.renderedComponent = renderedComponent;
// Mount the rendered output
return renderedComponent.mount();
}
}
This is not much different from our previous mountComposite()
implementation, but now we can save some information, such as this.currentElement
, this.renderedComponent
, and this.publicInstance
, for use during updates.
Note that an instance of CompositeComponent
is not the same thing as an instance of the user-supplied element.type
.
CompositeComponent
is an implementation detail of our reconciler, and is never exposed to the user.
The user-defined class is the one we read from element.type
, and CompositeComponent
creates an instance of it.
To avoid the confusion, we will call instances of CompositeComponent
and DOMComponent
¡°internal instances¡±.
They exist so we can associate some long-lived data with them.
Only the renderer and the reconciler are aware that they exist.
In contrast, we call an instance of the user-defined class a ¡°public instance¡±.
The public instance is what you see as this
in the render()
and other methods of your custom components.
The mountHost()
function, refactored to be a mount()
method on DOMComponent
class, also looks familiar:
class DOMComponent {
constructor(element) {
this.currentElement = element;
this.renderedChildren = [];
this.node = null;
}
getPublicInstance() {
// For DOM components, only expose the DOM node.
return this.node;
}
mount() {
var element = this.currentElement;
var type = element.type;
var props = element.props;
var children = props.children || [];
if (!Array.isArray(children)) {
children = [children];
}
// Create and save the node
var node = document.createElement(type);
this.node = node;
// Set the attributes
Object.keys(props).forEach(propName => {
if (propName !== 'children') {
node.setAttribute(propName, props[propName]);
}
});
// Create and save the contained children.
// Each of them can be a DOMComponent or a CompositeComponent,
// depending on whether the element type is a string or a function.
var renderedChildren = children.map(instantiateComponent);
this.renderedChildren = renderedChildren;
// Collect DOM nodes they return on mount
var childNodes = renderedChildren.map(child => child.mount());
childNodes.forEach(childNode => node.appendChild(childNode));
// Return the DOM node as mount result
return node;
}
}
The main difference after refactoring from mountHost()
is that we now keep this.node
and this.renderedChildren
associated with the internal DOM component instance.
We will also use them for applying non-destructive updates in the future.
As a result, each internal instance, composite or host, now points to its child internal instances.
To help visualize this, if a function <App>
component renders a <Button>
class component, and Button
class renders a <div>
, the internal instance tree would look like this:
[object CompositeComponent] {
currentElement: <App />,
publicInstance: null,
renderedComponent: [object CompositeComponent] {
currentElement: <Button />,
publicInstance: [object Button],
renderedComponent: [object DOMComponent] {
currentElement: <div />,
node: [object HTMLDivElement],
renderedChildren: []
}
}
}
In the DOM you would only see the <div>
.
However the internal instance tree contains both composite and host internal instances.
The composite internal instances need to store:
- The current element.
- The public instance if element type is a class.
- The single rendered internal instance.
It can be either a
DOMComponent
or a CompositeComponent
.
The host internal instances need to store:
- The current element.
- The DOM node.
- All the child internal instances.
Each of them can be either a
DOMComponent
or a CompositeComponent
.
If you're struggling to imagine how an internal instance tree is structured in more complex applications, React DevTools can give you a close approximation, as it highlights host instances with grey, and composite instances with purple:
To complete this refactoring, we will introduce a function that mounts a complete tree into a container node, just like ReactDOM.render()
.
It returns a public instance, also like ReactDOM.render()
:
function mountTree(element, containerNode) {
// Create the top-level internal instance
var rootComponent = instantiateComponent(element);
// Mount the top-level component into the container
var node = rootComponent.mount();
containerNode.appendChild(node);
// Return the public instance it provides
var publicInstance = rootComponent.getPublicInstance();
return publicInstance;
}
var rootEl = document.getElementById('root');
mountTree(<App />, rootEl);
Unmounting
Now that we have internal instances that hold onto their children and the DOM nodes, we can implement unmounting.
For a composite component, unmounting calls a lifecycle method and recurses.
class CompositeComponent {
// ...
unmount() {
// Call the lifecycle method if necessary
var publicInstance = this.publicInstance;
if (publicInstance) {
if (publicInstance.componentWillUnmount) {
publicInstance.componentWillUnmount();
}
}
// Unmount the single rendered component
var renderedComponent = this.renderedComponent;
renderedComponent.unmount();
}
}
For DOMComponent
, unmounting tells each child to unmount:
class DOMComponent {
// ...
unmount() {
// Unmount all the children
var renderedChildren = this.renderedChildren;
renderedChildren.forEach(child => child.unmount());
}
}
In practice, unmounting DOM components also removes the event listeners and clears some caches, but we will skip those details.
We can now add a new top-level function called unmountTree(containerNode)
that is similar to ReactDOM.unmountComponentAtNode()
:
function unmountTree(containerNode) {
// Read the internal instance from a DOM node:
// (This doesn't work yet, we will need to change mountTree() to store it.)
var node = containerNode.firstChild;
var rootComponent = node._internalInstance;
// Unmount the tree and clear the container
rootComponent.unmount();
containerNode.innerHTML = '';
}
In order for this to work, we need to read an internal root instance from a DOM node.
We will modify mountTree()
to add the _internalInstance
property to the root DOM node.
We will also teach mountTree()
to destroy any existing tree so it can be called multiple times:
function mountTree(element, containerNode) {
// Destroy any existing tree
if (containerNode.firstChild) {
unmountTree(containerNode);
}
// Create the top-level internal instance
var rootComponent = instantiateComponent(element);
// Mount the top-level component into the container
var node = rootComponent.mount();
containerNode.appendChild(node);
// Save a reference to the internal instance
node._internalInstance = rootComponent;
// Return the public instance it provides
var publicInstance = rootComponent.getPublicInstance();
return publicInstance;
}
Now, running unmountTree()
, or running mountTree()
repeatedly, removes the old tree and runs the componentWillUnmount()
lifecycle method on components.
Updating
In the previous section, we implemented unmounting.
However React wouldn't be very useful if each prop change unmounted and mounted the whole tree.
The goal of the reconciler is to reuse existing instances where possible to preserve the DOM and the state:
var rootEl = document.getElementById('root');
mountTree(<App />, rootEl);
// Should reuse the existing DOM:
mountTree(<App />, rootEl);
We will extend our internal instance contract with one more method.
In addition to mount()
and unmount()
, both DOMComponent
and CompositeComponent
will implement a new method called receive(nextElement)
:
class CompositeComponent {
// ...
receive(nextElement) {
// ...
}
}
class DOMComponent {
// ...
receive(nextElement) {
// ...
}
}
Its job is to do whatever is necessary to bring the component (and any of its children) up to date with the description provided by the nextElement
.
This is the part that is often described as ¡°virtual DOM diffing¡± although what really happens is that we walk the internal tree recursively and let each internal instance receive an update.
Updating Composite Components
When a composite component receives a new element, we run the componentWillUpdate()
lifecycle method.
Then we re-render the component with the new props, and get the next rendered element:
class CompositeComponent {
// ...
receive(nextElement) {
var prevProps = this.currentElement.props;
var publicInstance = this.publicInstance;
var prevRenderedComponent = this.renderedComponent;
var prevRenderedElement = prevRenderedComponent.currentElement;
// Update *own* element
this.currentElement = nextElement;
var type = nextElement.type;
var nextProps = nextElement.props;
// Figure out what the next render() output is
var nextRenderedElement;
if (isClass(type)) {
// Component class
// Call the lifecycle if necessary
if (publicInstance.componentWillUpdate) {
publicInstance.componentWillUpdate(nextProps);
}
// Update the props
publicInstance.props = nextProps;
// Re-render
nextRenderedElement = publicInstance.render();
} else if (typeof type === 'function') {
// Component function
nextRenderedElement = type(nextProps);
}
// ...
Next, we can look at the rendered element's type
.
If the type
has not changed since the last render, the component below can also be updated in place.
For example, if it returned <Button color="red" />
the first time, and <Button color="blue" />
the second time, we can just tell the corresponding internal instance to receive()
the next element:
// ...
// If the rendered element type has not changed,
// reuse the existing component instance and exit.
if (prevRenderedElement.type === nextRenderedElement.type) {
prevRenderedComponent.receive(nextRenderedElement);
return;
}
// ...
However, if the next rendered element has a different type
than the previously rendered element, we can't update the internal instance.
A <button>
can't ¡°become¡± an <input>
.
Instead, we have to unmount the existing internal instance and mount the new one corresponding to the rendered element type.
For example, this is what happens when a component that previously rendered a <button />
renders an <input />
:
// ...
// If we reached this point, we need to unmount the previously
// mounted component, mount the new one, and swap their nodes.
// Find the old node because it will need to be replaced
var prevNode = prevRenderedComponent.getHostNode();
// Unmount the old child and mount a new child
prevRenderedComponent.unmount();
var nextRenderedComponent = instantiateComponent(nextRenderedElement);
var nextNode = nextRenderedComponent.mount();
// Replace the reference to the child
this.renderedComponent = nextRenderedComponent;
// Replace the old node with the new one
// Note: this is renderer-specific code and
// ideally should live outside of CompositeComponent:
prevNode.parentNode.replaceChild(nextNode, prevNode);
}
}
To sum this up, when a composite component receives a new element, it may either delegate the update to its rendered internal instance, or unmount it and mount a new one in its place.
There is another condition under which a component will re-mount rather than receive an element, and that is when the element's key
has changed.
We don't discuss key
handling in this document because it adds more complexity to an already complex tutorial.
Note that we needed to add a method called getHostNode()
to the internal instance contract so that it's possible to locate the platform-specific node and replace it during the update.
Its implementation is straightforward for both classes:
class CompositeComponent {
// ...
getHostNode() {
// Ask the rendered component to provide it.
// This will recursively drill down any composites.
return this.renderedComponent.getHostNode();
}
}
class DOMComponent {
// ...
getHostNode() {
return this.node;
}
}
Updating Host Components
Host component implementations, such as DOMComponent
, update differently.
When they receive an element, they need to update the underlying platform-specific view.
In case of React DOM, this means updating the DOM attributes:
class DOMComponent {
// ...
receive(nextElement) {
var node = this.node;
var prevElement = this.currentElement;
var prevProps = prevElement.props;
var nextProps = nextElement.props;
this.currentElement = nextElement;
// Remove old attributes.
Object.keys(prevProps).forEach(propName => {
if (propName !== 'children' && !nextProps.hasOwnProperty(propName)) {
node.removeAttribute(propName);
}
});
// Set next attributes.
Object.keys(nextProps).forEach(propName => {
if (propName !== 'children') {
node.setAttribute(propName, nextProps[propName]);
}
});
// ...
Then, host components need to update their children.
Unlike composite components, they might contain more than a single child.
In this simplified example, we use an array of internal instances and iterate over it, either updating or replacing the internal instances depending on whether the received type
matches their previous type
.
The real reconciler also takes element's key
in the account and track moves in addition to insertions and deletions, but we will omit this logic.
We collect DOM operations on children in a list so we can execute them in batch:
// ...
// These are arrays of React elements:
var prevChildren = prevProps.children || [];
if (!Array.isArray(prevChildren)) {
prevChildren = [prevChildren];
}
var nextChildren = nextProps.children || [];
if (!Array.isArray(nextChildren)) {
nextChildren = [nextChildren];
}
// These are arrays of internal instances:
var prevRenderedChildren = this.renderedChildren;
var nextRenderedChildren = [];
// As we iterate over children, we will add operations to the array.
var operationQueue = [];
// Note: the section below is extremely simplified!
// It doesn't handle reorders, children with holes, or keys.
// It only exists to illustrate the overall flow, not the specifics.
for (var i = 0; i < nextChildren.length; i++) {
// Try to get an existing internal instance for this child
var prevChild = prevRenderedChildren[i];
// If there is no internal instance under this index,
// a child has been appended to the end.
Create a new
// internal instance, mount it, and use its node.
if (!prevChild) {
var nextChild = instantiateComponent(nextChildren[i]);
var node = nextChild.mount();
// Record that we need to append a node
operationQueue.push({type: 'ADD', node});
nextRenderedChildren.push(nextChild);
continue;
}
// We can only update the instance if its element's type matches.
// For example, <Button size="small" /> can be updated to
// <Button size="large" /> but not to an <App />.
var canUpdate = prevChildren[i].type === nextChildren[i].type;
// If we can't update an existing instance, we have to unmount it
// and mount a new one instead of it.
if (!canUpdate) {
var prevNode = prevChild.getHostNode();
prevChild.unmount();
var nextChild = instantiateComponent(nextChildren[i]);
var nextNode = nextChild.mount();
// Record that we need to swap the nodes
operationQueue.push({type: 'REPLACE', prevNode, nextNode});
nextRenderedChildren.push(nextChild);
continue;
}
// If we can update an existing internal instance,
// just let it receive the next element and handle its own update.
prevChild.receive(nextChildren[i]);
nextRenderedChildren.push(prevChild);
}
// Finally, unmount any children that don't exist:
for (var j = nextChildren.length; j < prevChildren.length; j++) {
var prevChild = prevRenderedChildren[j];
var node = prevChild.getHostNode();
prevChild.unmount();
// Record that we need to remove the node
operationQueue.push({type: 'REMOVE', node});
}
// Point the list of rendered children to the updated version.
this.renderedChildren = nextRenderedChildren;
// ...
As the last step, we execute the DOM operations.
Again, the real reconciler code is more complex because it also handles moves:
// ...
// Process the operation queue.
while (operationQueue.length > 0) {
var operation = operationQueue.shift();
switch (operation.type) {
case 'ADD':
this.node.appendChild(operation.node);
break;
case 'REPLACE':
this.node.replaceChild(operation.nextNode, operation.prevNode);
break;
case 'REMOVE':
this.node.removeChild(operation.node);
break;
}
}
}
}
And that is it for updating host components.
Top-Level Updates
Now that both CompositeComponent
and DOMComponent
implement the receive(nextElement)
method, we can change the top-level mountTree()
function to use it when the element type
is the same as it was the last time:
function mountTree(element, containerNode) {
// Check for an existing tree
if (containerNode.firstChild) {
var prevNode = containerNode.firstChild;
var prevRootComponent = prevNode._internalInstance;
var prevElement = prevRootComponent.currentElement;
// If we can, reuse the existing root component
if (prevElement.type === element.type) {
prevRootComponent.receive(element);
return;
}
// Otherwise, unmount the existing tree
unmountTree(containerNode);
}
// ...
}
Now calling mountTree()
two times with the same type isn't destructive:
var rootEl = document.getElementById('root');
mountTree(<App />, rootEl);
// Reuses the existing DOM:
mountTree(<App />, rootEl);
These are the basics of how React works internally.
What We Left Out
This document is simplified compared to the real codebase.
There are a few important aspects we didn't address:
- Components can render
null
, and the reconciler can handle ¡°empty slots¡± in arrays and rendered output.
- The reconciler also reads
key
from the elements, and uses it to establish which internal instance corresponds to which element in an array.
A bulk of complexity in the actual React implementation is related to that.
- In addition to composite and host internal instance classes, there are also classes for ¡°text¡± and ¡°empty¡± components.
They represent text nodes and the ¡°empty slots¡± you get by rendering
null
.
- Renderers use injection to pass the host internal class to the reconciler.
For example, React DOM tells the reconciler to use
ReactDOMComponent
as the host internal instance implementation.
- The logic for updating the list of children is extracted into a mixin called
ReactMultiChild
which is used by the host internal instance class implementations both in React DOM and React Native.
- The reconciler also implements support for
setState()
in composite components.
Multiple updates inside event handlers get batched into a single update.
- The reconciler also takes care of attaching and detaching refs to composite components and host nodes.
- Lifecycle methods that are called after the DOM is ready, such as
componentDidMount()
and componentDidUpdate()
, get collected into ¡°callback queues¡± and are executed in a single batch.
- React puts information about the current update into an internal object called ¡°transaction¡±.
Transactions are useful for keeping track of the queue of pending lifecycle methods, the current DOM nesting for the warnings, and anything else that is ¡°global¡± to a specific update.
Transactions also ensure React ¡°cleans everything up¡± after updates.
For example, the transaction class provided by React DOM restores the input selection after any update.
Jumping into the Code
-
ReactMount
is where the code like mountTree()
and unmountTree()
from this tutorial lives.
It takes care of mounting and unmounting top-level components.
ReactNativeMount
is its React Native analog.
-
ReactDOMComponent
is the equivalent of DOMComponent
in this tutorial.
It implements the host component class for React DOM renderer.
ReactNativeBaseComponent
is its React Native analog.
-
ReactCompositeComponent
is the equivalent of CompositeComponent
in this tutorial.
It handles calling user-defined components and maintaining their state.
-
instantiateReactComponent
contains the switch that picks the right internal instance class to construct for an element.
It is equivalent to instantiateComponent()
in this tutorial.
-
ReactReconciler
is a wrapper with mountComponent()
, receiveComponent()
, and unmountComponent()
methods.
It calls the underlying implementations on the internal instances, but also includes some code around them that is shared by all internal instance implementations.
-
ReactChildReconciler
implements the logic for mounting, updating, and unmounting children according to the key
of their elements.
-
ReactMultiChild
implements processing the operation queue for child insertions, deletions, and moves independently of the renderer.
-
mount()
, receive()
, and unmount()
are really called mountComponent()
, receiveComponent()
, and unmountComponent()
in React codebase for legacy reasons, but they receive elements.
- Properties on the internal instances start with an underscore, e.g.
_currentElement
.
They are considered to be read-only public fields throughout the codebase.
Future Directions
Stack reconciler has inherent limitations such as being synchronous and unable to interrupt the work or split it in chunks.
There is a work in progress on the new Fiber reconciler with a completely different architecture.
In the future, we intend to replace stack reconciler with it, but at the moment it is far from feature parity.
Next Steps
Read the next section to learn about the guiding principles we use for React development.
Design Principles
We wrote this document so that you have a better idea of how we decide what React does and what React doesn't do, and what our development philosophy is like.
While we are excited to see community contributions, we are not likely to choose a path that violates one or more of these principles.
Note:
This document assumes a strong understanding of React.
It describes the design principles of React itself, not React components or applications.
For an introduction to React, check out Thinking in React instead.
Composition
The key feature of React is composition of components.
Components written by different people should work well together.
It is important to us that you can add functionality to a component without causing rippling changes throughout the codebase.
For example, it should be possible to introduce some local state into a component without changing any of the components using it.
Similarly, it should be possible to add some initialization and teardown code to any component when necessary.
There is nothing ¡°bad¡± about using state or lifecycle methods in components.
Like any powerful feature, they should be used in moderation, but we have no intention to remove them.
On the contrary, we think they are integral parts of what makes React useful.
We might enable more functional patterns in the future, but both local state and lifecycle methods will be a part of that model.
Components are often described as ¡°just functions¡± but in our view they need to be more than that to be useful.
In React, components describe any composable behavior, and this includes rendering, lifecycle, and state.
Some external libraries like Relay augment components with other responsibilities such as describing data dependencies.
It is possible that those ideas might make it back into React too in some form.
Common Abstraction
In general we resist adding features that can be implemented in userland.
We don't want to bloat your apps with useless library code.
However, there are exceptions to this.
For example, if React didn't provide support for local state or lifecycle methods, people would create custom abstractions for them.
When there are multiple abstractions competing, React can't enforce or take advantage of the properties of either of them.
It has to work with the lowest common denominator.
This is why sometimes we add features to React itself.
If we notice that many components implement a certain feature in incompatible or inefficient ways, we might prefer to bake it into React.
We don't do it lightly.
When we do it, it's because we are confident that raising the abstraction level benefits the whole ecosystem.
State, lifecycle methods, cross-browser event normalization are good examples of this.
We always discuss such improvement proposals with the community.
You can find some of those discussions by the ¡°big picture¡± label on the React issue tracker.
Escape Hatches
React is pragmatic.
It is driven by the needs of the products written at Facebook.
While it is influenced by some paradigms that are not yet fully mainstream such as functional programming, staying accessible to a wide range of developers with different skills and experience levels is an explicit goal of the project.
If we want to deprecate a pattern that we don't like, it is our responsibility to consider all existing use cases for it and educate the community about the alternatives before we deprecate it.
If some pattern that is useful for building apps is hard to express in a declarative way, we will provide an imperative API for it.
If we can't figure out a perfect API for something that we found necessary in many apps, we will provide a temporary subpar working API as long as it is possible to get rid of it later and it leaves the door open for future improvements.
Stability
We value API stability.
At Facebook, we have more than 50 thousand components using React.
Many other companies, including Twitter and Airbnb, are also heavy users of React.
This is why we are usually reluctant to change public APIs or behavior.
However we think stability in the sense of ¡°nothing changes¡± is overrated.
It quickly turns into stagnation.
Instead, we prefer the stability in the sense of ¡°It is heavily used in production, and when something changes, there is a clear (and preferably automated) migration path.¡±
When we deprecate a pattern, we study its internal usage at Facebook and add deprecation warnings.
They let us assess the impact of the change.
Sometimes we back out if we see that it is too early, and we need to think more strategically about getting the codebases to the point where they are ready for this change.
If we are confident that the change is not too disruptive and the migration strategy is viable for all use cases, we release the deprecation warning to the open source community.
We are closely in touch with many users of React outside of Facebook, and we monitor popular open source projects and guide them in fixing those deprecations.
Given the sheer size of the Facebook React codebase, successful internal migration is often a good indicator that other companies won't have problems either.
Nevertheless sometimes people point out additional use cases we haven't thought of, and we add escape hatches for them or rethink our approach.
We don't deprecate anything without a good reason.
We recognize that sometimes deprecations warnings cause frustration but we add them because deprecations clean up the road for the improvements and new features that we and many people in the community consider valuable.
For example, we added a warning about unknown DOM props in React 15.2.0.
Many projects were affected by this.
However fixing this warning is important so that we can introduce the support for custom attributes to React.
There is a reason like this behind every deprecation that we add.
When we add a deprecation warning, we keep it for the rest of the current major version, and change the behavior in the next major version.
If there is a lot of repetitive manual work involved, we release a codemod script that automates most of the change.
Codemods enable us to move forward without stagnation in a massive codebase, and we encourage you to use them as well.
You can find the codemods that we released in the react-codemod repository.
Interoperability
We place high value in interoperability with existing systems and gradual adoption.
Facebook has a massive non-React codebase.
Its website uses a mix of a server-side component system called XHP, internal UI libraries that came before React, and React itself.
It is important to us that any product team can start using React for a small feature rather than rewrite their code to bet on it.
This is why React provides escape hatches to work with mutable models, and tries to work well together with other UI libraries.
You can wrap an existing imperative UI into a declarative component, and vice versa.
This is crucial for gradual adoption.
Scheduling
Even when your components are described as functions, when you use React you don't call them directly.
Every component returns a description of what needs to be rendered, and that description may include both user-written components like <LikeButton>
and platform-specific components like <div>
.
It is up to React to ¡°unroll¡± <LikeButton>
at some point in the future and actually apply changes to the UI tree according to the render results of the components recursively.
This is a subtle distinction but a powerful one.
Since you don't call that component function but let React call it, it means React has the power to delay calling it if necessary.
In its current implementation React walks the tree recursively and calls render functions of the whole updated tree during a single tick.
However in the future it might start delaying some updates to avoid dropping frames.
This is a common theme in React design.
Some popular libraries implement the ¡°push¡± approach where computations are performed when the new data is available.
React, however, sticks to the ¡°pull¡± approach where computations can be delayed until necessary.
React is not a generic data processing library.
It is a library for building user interfaces.
We think that it is uniquely positioned in an app to know which computations are relevant right now and which are not.
If something is offscreen, we can delay any logic related to it.
If data is arriving faster than the frame rate, we can coalesce and batch updates.
We can prioritize work coming from user interactions (such as an animation caused by a button click) over less important background work (such as rendering new content just loaded from the network) to avoid dropping frames.
To be clear, we are not taking advantage of this right now.
However the freedom to do something like this is why we prefer to have control over scheduling, and why setState()
is asynchronous.
Conceptually, we think of it as ¡°scheduling an update¡±.
The control over scheduling would be harder for us to gain if we let the user directly compose views with a ¡°push¡± based paradigm common in some variations of Functional Reactive Programming.
We want to own the ¡°glue¡± code.
It is a key goal for React that the amount of the user code that executes before yielding back into React is minimal.
This ensures that React retains the capability to schedule and split work in chunks according to what it knows about the UI.
There is an internal joke in the team that React should have been called ¡°Schedule¡± because React does not want to be fully ¡°reactive¡±.
Developer Experience
Providing a good developer experience is important to us.
For example, we maintain React DevTools which let you inspect the React component tree in Chrome and Firefox.
We have heard that it brings a big productivity boost both to the Facebook engineers and to the community.
We also try to go an extra mile to provide helpful developer warnings.
For example, React warns you in development if you nest tags in a way that the browser doesn't understand, or if you make a common typo in the API.
Developer warnings and the related checks are the main reason why the development version of React is slower than the production version.
The usage patterns that we see internally at Facebook help us understand what the common mistakes are, and how to prevent them early.
When we add new features, we try to anticipate the common mistakes and warn about them.
We are always looking out for ways to improve the developer experience.
We love to hear your suggestions and accept your contributions to make it even better.
Debugging
When something goes wrong, it is important that you have breadcrumbs to trace the mistake to its source in the codebase.
In React, props and state are those breadcrumbs.
If you see something wrong on the screen, you can open React DevTools, find the component responsible for rendering, and then see if the props and state are correct.
If they are, you know that the problem is in the component's render()
function, or some function that is called by render()
.
The problem is isolated.
If the state is wrong, you know that the problem is caused by one of the setState()
calls in this file.
This, too, is relatively simple to locate and fix because usually there are only a few setState()
calls in a single file.
If the props are wrong, you can traverse the tree up in the inspector, looking for the component that first ¡°poisoned the well¡± by passing bad props down.
This ability to trace any UI to the data that produced it in the form of current props and state is very important to React.
It is an explicit design goal that state is not ¡°trapped¡± in closures and combinators, and is available to React directly.
While the UI is dynamic, we believe that synchronous render()
functions of props and state turn debugging from guesswork into a boring but finite procedure.
We would like to preserve this constraint in React even though it makes some use cases, like complex animations, harder.
Configuration
We find global runtime configuration options to be problematic.
For example, it is occasionally requested that we implement a function like React.configure(options)
or React.register(component)
.
However this poses multiple problems, and we are not aware of good solutions to them.
What if somebody calls such a function from a third-party component library? What if one React app embeds another React app, and their desired configurations are incompatible? How can a third-party component specify that it requires a particular configuration? We think that global configuration doesn't work well with composition.
Since composition is central to React, we don't provide global configuration in code.
We do, however, provide some global configuration on the build level.
For example, we provide separate development and production builds.
We may also add a profiling build in the future, and we are open to considering other build flags.
Beyond the DOM
We see the value of React in the way it allows us to write components that have fewer bugs and compose together well.
DOM is the original rendering target for React but React Native is just as important both to Facebook and the community.
Being renderer-agnostic is an important design constraint of React.
It adds some overhead in the internal representations.
On the other hand, any improvements to the core translate across platforms.
Having a single programming model lets us form engineering teams around products instead of platforms.
So far the tradeoff has been worth it for us.
Implementation
We try to provide elegant APIs where possible.
We are much less concerned with the implementation being elegant.
The real world is far from perfect, and to a reasonable extent we prefer to put the ugly code into the library if it means the user does not have to write it.
When we evaluate new code, we are looking for an implementation that is correct, performant and affords a good developer experience.
Elegance is secondary.
We prefer boring code to clever code.
Code is disposable and often changes.
So it is important that it doesn't introduce new internal abstractions unless absolutely necessary.
Verbose code that is easy to move around, change and remove is preferred to elegant code that is prematurely abstracted and hard to change.
Optimized for Tooling
Some commonly used APIs have verbose names.
For example, we use componentDidMount()
instead of didMount()
or onMount()
.
This is intentional.
The goal is to make the points of interaction with the library highly visible.
In a massive codebase like Facebook, being able to search for uses of specific APIs is very important.
We value distinct verbose names, and especially for the features that should be used sparingly.
For example, dangerouslySetInnerHTML
is hard to miss in a code review.
Optimizing for search is also important because of our reliance on codemods to make breaking changes.
We want it to be easy and safe to apply vast automated changes across the codebase, and unique verbose names help us achieve this.
Similarly, distinctive names make it easy to write custom lint rules about using React without worrying about potential false positives.
JSX plays a similar role.
While it is not required with React, we use it extensively at Facebook both for aesthetic and pragmatic reasons.
In our codebase, JSX provides an unambiguous hint to the tools that they are dealing with a React element tree.
This makes it possible to add build-time optimizations such as hoisting constant elements, safely lint and codemod internal component usage, and include JSX source location into the warnings.
Dogfooding
We try our best to address the problems raised by the community.
However we are likely to prioritize the issues that people are also experiencing internally at Facebook.
Perhaps counter-intuitively, we think this is the main reason why the community can bet on React.
Heavy internal usage gives us the confidence that React won't disappear tomorrow.
React was created at Facebook to solve its problems.
It brings tangible business value to the company and is used in many of its products.
Dogfooding it means that our vision stays sharp and we have a focused direction going forward.
This doesn't mean that we ignore the issues raised by the community.
For example, we added support for web components and SVG to React even though we don't rely on either of them internally.
We are actively listening to your pain points and address them to the best of our ability.
The community is what makes React special to us, and we are honored to contribute back.
After releasing many open source projects at Facebook, we have learned that trying to make everyone happy at the same time produced projects with poor focus that didn't grow well.
Instead, we found that picking a small audience and focusing on making them happy brings a positive net effect.
That's exactly what we did with React, and so far solving the problems encountered by Facebook product teams has translated well to the open source community.
The downside of this approach is that sometimes we fail to give enough focus to the things that Facebook teams don't have to deal with, such as the ¡°getting started¡± experience.
We are acutely aware of this, and we are thinking of how to improve in a way that would benefit everyone in the community without making the same mistakes we did with open source projects before.
AJAX and APIs
How can I make an AJAX call?
You can use any AJAX library you like with React.
Some popular ones are Axios, jQuery AJAX, and the browser built-in window.fetch.
Where in the component lifecycle should I make an AJAX call?
You should populate data with AJAX calls in the componentDidMount
lifecycle method.
This is so you can use setState
to update your component when the data is retrieved.
Example: Using AJAX results to set local state
The component below demonstrates how to make an AJAX call in componentDidMount
to populate local component state.
The example API returns a JSON object like this:
{
"items": [
{ "id": 1, "name": "Apples", "price": "$2" },
{ "id": 2, "name": "Peaches", "price": "$5" }
]
}
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
items: []
};
}
componentDidMount() {
fetch("https://api.example.com/items")
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
items: result.items
});
},
// Note: it's important to handle errors here
// instead of a catch() block so that we don't swallow
// exceptions from actual bugs in components.
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
render() {
const { error, isLoaded, items } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<ul>
{items.map(item => (
<li key={item.id}>
{item.name} {item.price}
</li>
))}
</ul>
);
}
}
}
Here is the equivalent with Hooks:
function MyComponent() {
const [error, setError] = useState(null);
const [isLoaded, setIsLoaded] = useState(false);
const [items, setItems] = useState([]);
// Note: the empty deps array [] means
// this useEffect will run once
// similar to componentDidMount()
useEffect(() => {
fetch("https://api.example.com/items")
.then(res => res.json())
.then(
(result) => {
setIsLoaded(true);
setItems(result);
},
// Note: it's important to handle errors here
// instead of a catch() block so that we don't swallow
// exceptions from actual bugs in components.
(error) => {
setIsLoaded(true);
setError(error);
}
)
}, [])
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<ul>
{items.map(item => (
<li key={item.id}>
{item.name} {item.price}
</li>
))}
</ul>
);
}
}
Babel, JSX, and Build Steps
Do I need to use JSX with React?
No! Check out ¡°React Without JSX¡± to learn more.
Do I need to use ES6 (+) with React?
No! Check out ¡°React Without ES6¡± to learn more.
How can I write comments in JSX?
<div>
{/* Comment goes here */}
Hello, {name}!
</div>
<div>
{/* It also works
for multi-line comments.
*/}
Hello, {name}!
</div>
Passing Functions to Components
How do I pass an event handler (like onClick) to a component?
Pass event handlers and other functions as props to child components:
<button onClick={this.handleClick}>
If you need to have access to the parent component in the handler, you also need to bind the function to the component instance (see below).
How do I bind a function to a component instance?
There are several ways to make sure functions have access to component attributes like this.props
and this.state
, depending on which syntax and build steps you are using.
Bind in Constructor (ES2015)
class Foo extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log('Click happened');
}
render() {
return <button onClick={this.handleClick}>Click Me</button>;
}
}
Class Properties (Stage 3 Proposal)
class Foo extends Component {
// Note: this syntax is experimental and not standardized yet.
handleClick = () => {
console.log('Click happened');
}
render() {
return <button onClick={this.handleClick}>Click Me</button>;
}
}
Bind in Render
class Foo extends Component {
handleClick() {
console.log('Click happened');
}
render() {
return <button onClick={this.handleClick.bind(this)}>Click Me</button>;
}
}
Note:
Using Function.prototype.bind
in render creates a new function each time the component renders, which may have performance implications (see below).
Arrow Function in Render
class Foo extends Component {
handleClick() {
console.log('Click happened');
}
render() {
return <button onClick={() => this.handleClick()}>Click Me</button>;
}
}
Note:
Using an arrow function in render creates a new function each time the component renders, which may break optimizations based on strict identity comparison.
Is it OK to use arrow functions in render methods?
Generally speaking, yes, it is OK, and it is often the easiest way to pass parameters to callback functions.
If you do have performance issues, by all means, optimize!
Why is binding necessary at all?
In JavaScript, these two code snippets are not equivalent:
obj.method();
var method = obj.method;
method();
Binding methods helps ensure that the second snippet works the same way as the first one.
With React, typically you only need to bind the methods you pass to other components.
For example, <button onClick={this.handleClick}>
passes this.handleClick
so you want to bind it.
However, it is unnecessary to bind the render
method or the lifecycle methods: we don't pass them to other components.
This post by Yehuda Katz explains what binding is, and how functions work in JavaScript, in detail.
Why is my function being called every time the component renders?
Make sure you aren't calling the function when you pass it to the component:
render() {
// Wrong: handleClick is called instead of passed as a reference!
return <button onClick={this.handleClick()}>Click Me</button>
}
Instead, pass the function itself (without parens):
render() {
// Correct: handleClick is passed as a reference!
return <button onClick={this.handleClick}>Click Me</button>
}
How do I pass a parameter to an event handler or callback?
You can use an arrow function to wrap around an event handler and pass parameters:
<button onClick={() => this.handleClick(id)} />
This is equivalent to calling .bind
:
<button onClick={this.handleClick.bind(this, id)} />
Example: Passing params using arrow functions
const A = 65 // ASCII character code
class Alphabet extends React.Component {
constructor(props) {
super(props);
this.state = {
justClicked: null,
letters: Array.from({length: 26}, (_, i) => String.fromCharCode(A + i))
};
}
handleClick(letter) {
this.setState({ justClicked: letter });
}
render() {
return (
<div>
Just clicked: {this.state.justClicked}
<ul>
{this.state.letters.map(letter =>
<li key={letter} onClick={() => this.handleClick(letter)}>
{letter}
</li>
)}
</ul>
</div>
)
}
}
Example: Passing params using data-attributes
Alternately, you can use DOM APIs to store data needed for event handlers.
Consider this approach if you need to optimize a large number of elements or have a render tree that relies on React.PureComponent equality checks.
const A = 65 // ASCII character code
class Alphabet extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.state = {
justClicked: null,
letters: Array.from({length: 26}, (_, i) => String.fromCharCode(A + i))
};
}
handleClick(e) {
this.setState({
justClicked: e.target.dataset.letter
});
}
render() {
return (
<div>
Just clicked: {this.state.justClicked}
<ul>
{this.state.letters.map(letter =>
<li key={letter} data-letter={letter} onClick={this.handleClick}>
{letter}
</li>
)}
</ul>
</div>
)
}
}
How can I prevent a function from being called too quickly or too many times in a row?
If you have an event handler such as onClick
or onScroll
and want to prevent the callback from being fired too quickly, then you can limit the rate at which callback is executed.
This can be done by using:
-
throttling: sample changes based on a time based frequency (eg
_.throttle
)
-
debouncing: publish changes after a period of inactivity (eg
_.debounce
)
-
requestAnimationFrame
throttling: sample changes based on requestAnimationFrame
(eg raf-schd
)
See this visualization for a comparison of throttle
and debounce
functions.
Note:
_.debounce
, _.throttle
and raf-schd
provide a cancel
method to cancel delayed callbacks.
You should either call this method from componentWillUnmount
or check to ensure that the component is still mounted within the delayed function.
Throttle
Throttling prevents a function from being called more than once in a given window of time.
The example below throttles a ¡°click¡± handler to prevent calling it more than once per second.
import throttle from 'lodash.throttle';
class LoadMoreButton extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.handleClickThrottled = throttle(this.handleClick, 1000);
}
componentWillUnmount() {
this.handleClickThrottled.cancel();
}
render() {
return <button onClick={this.handleClickThrottled}>Load More</button>;
}
handleClick() {
this.props.loadMore();
}
}
Debounce
Debouncing ensures that a function will not be executed until after a certain amount of time has passed since it was last called.
This can be useful when you have to perform some expensive calculation in response to an event that might dispatch rapidly (eg scroll or keyboard events).
The example below debounces text input with a 250ms delay.
import debounce from 'lodash.debounce';
class Searchbox extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.emitChangeDebounced = debounce(this.emitChange, 250);
}
componentWillUnmount() {
this.emitChangeDebounced.cancel();
}
render() {
return (
<input
type="text"
onChange={this.handleChange}
placeholder="Search..."
defaultValue={this.props.value}
/>
);
}
handleChange(e) {
this.emitChangeDebounced(e.target.value);
}
emitChange(value) {
this.props.onChange(value);
}
}
requestAnimationFrame
throttling
requestAnimationFrame
is a way of queuing a function to be executed in the browser at the optimal time for rendering performance.
A function that is queued with requestAnimationFrame
will fire in the next frame.
The browser will work hard to ensure that there are 60 frames per second (60 fps).
However, if the browser is unable to it will naturally limit the amount of frames in a second.
For example, a device might only be able to handle 30 fps and so you will only get 30 frames in that second.
Using requestAnimationFrame
for throttling is a useful technique in that it prevents you from doing more than 60 updates in a second.
If you are doing 100 updates in a second this creates additional work for the browser that the user will not see anyway.
Note:
Using this technique will only capture the last published value in a frame.
You can see an example of how this optimization works on MDN
import rafSchedule from 'raf-schd';
class ScrollListener extends React.Component {
constructor(props) {
super(props);
this.handleScroll = this.handleScroll.bind(this);
// Create a new function to schedule updates.
this.scheduleUpdate = rafSchedule(
point => this.props.onScroll(point)
);
}
handleScroll(e) {
// When we receive a scroll event, schedule an update.
// If we receive many updates within a frame, we'll only publish the latest value.
this.scheduleUpdate({ x: e.clientX, y: e.clientY });
}
componentWillUnmount() {
// Cancel any pending updates since we're unmounting.
this.scheduleUpdate.cancel();
}
render() {
return (
<div
style={{ overflow: 'scroll' }}
onScroll={this.handleScroll}
>
<img src="/my-huge-image.jpg" />
</div>
);
}
}
Testing your rate limiting
When testing your rate limiting code works correctly it is helpful to have the ability to fast forward time.
If you are using jest
then you can use mock timers
to fast forward time.
If you are using requestAnimationFrame
throttling then you may find raf-stub
to be a useful tool to control the ticking of animation frames.
Component State
What does setState
do?
setState()
schedules an update to a component's state
object.
When state changes, the component responds by re-rendering.
What is the difference between state
and props
?
props
(short for ¡°properties¡±) and state
are both plain JavaScript objects.
While both hold information that influences the output of render, they are different in one important way: props
get passed to the component (similar to function parameters) whereas state
is managed within the component (similar to variables declared within a function).
Here are some good resources for further reading on when to use props
vs state
:
- Props vs State
- ReactJS: Props vs.
State
Why is setState
giving me the wrong value?
In React, both this.props
and this.state
represent the rendered values, i.e.
what's currently on the screen.
Calls to setState
are asynchronous - don't rely on this.state
to reflect the new value immediately after calling setState
.
Pass an updater function instead of an object if you need to compute values based on the current state (see below for details).
Example of code that will not behave as expected:
incrementCount() {
// Note: this will *not* work as intended.
this.setState({count: this.state.count + 1});
}
handleSomething() {
// Let's say `this.state.count` starts at 0.
this.incrementCount();
this.incrementCount();
this.incrementCount();
// When React re-renders the component, `this.state.count` will be 1, but you expected 3.
// This is because `incrementCount()` function above reads from `this.state.count`,
// but React doesn't update `this.state.count` until the component is re-rendered.
// So `incrementCount()` ends up reading `this.state.count` as 0 every time, and sets it to 1.
// The fix is described below!
}
See below for how to fix this problem.
How do I update state with values that depend on the current state?
Pass a function instead of an object to setState
to ensure the call always uses the most updated version of state (see below).
What is the difference between passing an object or a function in setState
?
Passing an update function allows you to access the current state value inside the updater.
Since setState
calls are batched, this lets you chain updates and ensure they build on top of each other instead of conflicting:
incrementCount() {
this.setState((state) => {
// Important: read `state` instead of `this.state` when updating.
return {count: state.count + 1}
});
}
handleSomething() {
// Let's say `this.state.count` starts at 0.
this.incrementCount();
this.incrementCount();
this.incrementCount();
// If you read `this.state.count` now, it would still be 0.
// But when React re-renders the component, it will be 3.
}
Learn more about setState
When is setState
asynchronous?
Currently, setState
is asynchronous inside event handlers.
This ensures, for example, that if both Parent
and Child
call setState
during a click event, Child
isn't re-rendered twice.
Instead, React ¡°flushes¡± the state updates at the end of the browser event.
This results in significant performance improvements in larger apps.
This is an implementation detail so avoid relying on it directly.
In the future versions, React will batch updates by default in more cases.
Why doesn't React update this.state
synchronously?
As explained in the previous section, React intentionally ¡°waits¡± until all components call setState()
in their event handlers before starting to re-render.
This boosts performance by avoiding unnecessary re-renders.
However, you might still be wondering why React doesn't just update this.state
immediately without re-rendering.
There are two main reasons:
- This would break the consistency between
props
and state
, causing issues that are very hard to debug.
- This would make some of the new features we're working on impossible to implement.
This GitHub comment dives deep into the specific examples.
Should I use a state management library like Redux or MobX?
Maybe.
It's a good idea to get to know React first, before adding in additional libraries.
You can build quite complex applications using only React.
Styling and CSS
How do I add CSS classes to components?
Pass a string as the className
prop:
render() {
return <span className="menu navigation-menu">Menu</span>
}
It is common for CSS classes to depend on the component props or state:
render() {
let className = 'menu';
if (this.props.isActive) {
className += ' menu-active';
}
return <span className={className}>Menu</span>
}
Tip
If you often find yourself writing code like this, classnames package can simplify it.
Can I use inline styles?
Yes, see the docs on styling here.
Are inline styles bad?
CSS classes are generally better for performance than inline styles.
What is CSS-in-JS?
¡°CSS-in-JS¡± refers to a pattern where CSS is composed using JavaScript instead of defined in external files.
Note that this functionality is not a part of React, but provided by third-party libraries. React does not have an opinion about how styles are defined; if in doubt, a good starting point is to define your styles in a separate *.css
file as usual and refer to them using className
.
Can I do animations in React?
React can be used to power animations.
See React Transition Group and React Motion or React Spring, for example.
File Structure
Is there a recommended way to structure React projects?
React doesn't have opinions on how you put files into folders.
That said there are a few common approaches popular in the ecosystem you may want to consider.
Grouping by features or routes
One common way to structure projects is to locate CSS, JS, and tests together inside folders grouped by feature or route.
common/
Avatar.js
Avatar.css
APIUtils.js
APIUtils.test.js
feed/
index.js
Feed.js
Feed.css
FeedStory.js
FeedStory.test.js
FeedAPI.js
profile/
index.js
Profile.js
ProfileHeader.js
ProfileHeader.css
ProfileAPI.js
The definition of a ¡°feature¡± is not universal, and it is up to you to choose the granularity.
If you can't come up with a list of top-level folders, you can ask the users of your product what major parts it consists of, and use their mental model as a blueprint.
Grouping by file type
Another popular way to structure projects is to group similar files together, for example:
api/
APIUtils.js
APIUtils.test.js
ProfileAPI.js
UserAPI.js
components/
Avatar.js
Avatar.css
Feed.js
Feed.css
FeedStory.js
FeedStory.test.js
Profile.js
ProfileHeader.js
ProfileHeader.css
Some people also prefer to go further, and separate components into different folders depending on their role in the application.
For example, Atomic Design is a design methodology built on this principle.
Remember that it's often more productive to treat such methodologies as helpful examples rather than strict rules to follow.
Avoid too much nesting
There are many pain points associated with deep directory nesting in JavaScript projects.
It becomes harder to write relative imports between them, or to update those imports when the files are moved.
Unless you have a very compelling reason to use a deep folder structure, consider limiting yourself to a maximum of three or four nested folders within a single project.
Of course, this is only a recommendation, and it may not be relevant to your project.
Don't overthink it
If you're just starting a project, don't spend more than five minutes on choosing a file structure.
Pick any of the above approaches (or come up with your own) and start writing code! You'll likely want to rethink it anyway after you've written some real code.
If you feel completely stuck, start by keeping all files in a single folder.
Eventually it will grow large enough that you will want to separate some files from the rest.
By that time you'll have enough knowledge to tell which files you edit together most often.
In general, it is a good idea to keep files that often change together close to each other.
This principle is called ¡°colocation¡±.
As projects grow larger, they often use a mix of both of the above approaches in practice.
So choosing the ¡°right¡± one in the beginning isn't very important.
Versioning Policy
React follows semantic versioning (semver) principles.
That means that with a version number x.y.z:
- When releasing critical bug fixes, we make a patch release by changing the z number (ex: 15.6.2 to 15.6.3).
- When releasing new features or non-critical fixes, we make a minor release by changing the y number (ex: 15.6.2 to 15.7.0).
- When releasing breaking changes, we make a major release by changing the x number (ex: 15.6.2 to 16.0.0).
Major releases can also contain new features, and any release can include bug fixes.
Minor releases are the most common type of release.
This versioning policy does not apply to prerelease builds in the Next or Experimental channels.
Learn more about prereleases.
Breaking Changes
Breaking changes are inconvenient for everyone, so we try to minimize the number of major releases ¨C for example, React 15 was released in April 2016 and React 16 was released in September 2017, and React 17 was released in October 2020.
Instead, we release new features in minor versions.
That means that minor releases are often more interesting and compelling than majors, despite their unassuming name.
Commitment to Stability
As we change React over time, we try to minimize the effort required to take advantage of new features.
When possible, we'll keep an older API working, even if that means putting it in a separate package.
For example, mixins have been discouraged for years but they're supported to this day via create-react-class and many codebases continue to use them in stable, legacy code.
Over a million developers use React, collectively maintaining millions of components.
The Facebook codebase alone has over 50,000 React components.
That means we need to make it as easy as possible to upgrade to new versions of React; if we make large changes without a migration path, people will be stuck on old versions.
We test these upgrade paths on Facebook itself ¨C if our team of less than 10 people can update 50,000+ components alone, we hope the upgrade will be manageable for anyone using React.
In many cases, we write automated scripts to upgrade component syntax, which we then include in the open-source release for everyone to use.
Gradual Upgrades via Warnings
Development builds of React include many helpful warnings.
Whenever possible, we add warnings in preparation for future breaking changes.
That way, if your app has no warnings on the latest release, it will be compatible with the next major release.
This allows you to upgrade your apps one component at a time.
Development warnings won't affect the runtime behavior of your app.
That way, you can feel confident that your app will behave the same way between the development and production builds ¡ª the only differences are that the production build won't log the warnings and that it is more efficient.
(If you ever notice otherwise, please file an issue.)
What Counts as a Breaking Change?
In general, we don't bump the major version number for changes to:
-
Development warnings. Since these don't affect production behavior, we may add new warnings or modify existing warnings in between major versions.
In fact, this is what allows us to reliably warn about upcoming breaking changes.
-
APIs starting with
unstable_
. These are provided as experimental features whose APIs we are not yet confident in.
By releasing these with an unstable_
prefix, we can iterate faster and get to a stable API sooner.
-
Alpha and canary versions of React. We provide alpha versions of React as a way to test new features early, but we need the flexibility to make changes based on what we learn in the alpha period.
If you use these versions, note that APIs may change before the stable release.
-
Undocumented APIs and internal data structures. If you access internal property names like
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
or __reactInternalInstance$uk43rzhitjg
, there is no warranty.
You are on your own.
This policy is designed to be pragmatic: certainly, we don't want to cause headaches for you.
If we bumped the major version for all of these changes, we would end up releasing more major versions and ultimately causing more versioning pain for the community.
It would also mean that we can't make progress in improving React as fast as we'd like.
That said, if we expect that a change on this list will cause broad problems in the community, we will still do our best to provide a gradual migration path.
If a Minor Release Includes No New Features, Why Isn't It a Patch?
It's possible that a minor release will not include new features.
This is allowed by semver, which states ¡±[a minor version] MAY be incremented if substantial new functionality or improvements are introduced within the private code.
It MAY include patch level changes.¡±
However, it does raise the question of why these releases aren't versioned as patches instead.
The answer is that any change to React (or other software) carries some risk of breaking in unexpected ways.
Imagine a scenario where a patch release that fixes one bug accidentally introduces a different bug.
This would not only be disruptive to developers, but also harm their confidence in future patch releases.
It's especially regrettable if the original fix is for a bug that is rarely encountered in practice.
We have a pretty good track record for keeping React releases free of bugs, but patch releases have an even higher bar for reliability because most developers assume they can be adopted without adverse consequences.
For these reasons, we reserve patch releases only for the most critical bugs and security vulnerabilities.
If a release includes non-essential changes ¡ª such as internal refactors, changes to implementation details, performance improvements, or minor bugfixes ¡ª we will bump the minor version even when there are no new features.
Virtual DOM and Internals
What is the Virtual DOM?
The virtual DOM (VDOM) is a programming concept where an ideal, or ¡°virtual¡±, representation of a UI is kept in memory and synced with the ¡°real¡± DOM by a library such as ReactDOM.
This process is called reconciliation.
This approach enables the declarative API of React: You tell React what state you want the UI to be in, and it makes sure the DOM matches that state.
This abstracts out the attribute manipulation, event handling, and manual DOM updating that you would otherwise have to use to build your app.
Since ¡°virtual DOM¡± is more of a pattern than a specific technology, people sometimes say it to mean different things.
In React world, the term ¡°virtual DOM¡± is usually associated with React elements since they are the objects representing the user interface.
React, however, also uses internal objects called ¡°fibers¡± to hold additional information about the component tree.
They may also be considered a part of ¡°virtual DOM¡± implementation in React.
Is the Shadow DOM the same as the Virtual DOM?
No, they are different.
The Shadow DOM is a browser technology designed primarily for scoping variables and CSS in web components.
The virtual DOM is a concept implemented by libraries in JavaScript on top of browser APIs.
What is ¡°React Fiber¡±?
Fiber is the new reconciliation engine in React 16.
Its main goal is to enable incremental rendering of the virtual DOM.
Read more.