×

Welcome to Knowledge Base!

KB at your finger tips

This is one stop global knowledge base where you can learn about all the products, solutions and support features.

Categories
All
Web-React
Thinking in React – React

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:





Mockup



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.





Diagram showing nesting of components



You’ll see here that we have five components in our app. We’ve italicized the data each component represents. The numbers in the image correspond to the numbers below.



  1. FilterableProductTable (orange): contains the entirety of the example

  2. SearchBar (blue): receives all user input

  3. ProductTable (green): displays and filters the data collection based on user input

  4. ProductCategoryRow (turquoise): displays a heading for each category

  5. 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 root.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 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:



  1. Is it passed in from a parent via props? If so, it probably isn’t state.

  2. Does it remain unchanged over time? If so, it probably isn’t state.

  3. 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 previous version of the example (step 4), 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 often 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. :)

Is this page useful? Edit this page
Accessibility – React

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 id="namedInput" type="text" name="name"/>

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:







Blue keyboard focus outline around a selected link.





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:



  • Accessible Landmarks


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.


A toggle button opening a popover list implemented with the click outside pattern and operated with a mouse showing that the close action works.

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.


A toggle button opening a popover list implemented with the click outside pattern and operated with the keyboard showing the popover not being closed on blur and it obscuring other screen elements.

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.


A popover list correctly closing for both mouse and keyboard users.

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:



  • ARIA Authoring Practices Guide (APG) - Design Patterns and Examples

  • 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:



  1. Disconnecting your mouse.

  2. Using Tab and Shift+Tab to browse.

  3. Using Enter to activate elements.

  4. 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 @axe-core/react 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

Is this page useful? Edit this page
Read article
Code-Splitting – React

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 set up 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


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>
);
}

Avoiding fallbacks


Any component may suspend as a result of rendering, even components that were already shown to the user. In order for screen content to always be consistent, if an already shown component suspends, React has to hide its tree up to the closest <Suspense> boundary. However, from the user’s perspective, this can be disorienting.


Consider this tab switcher:


import React, { Suspense } from 'react';
import Tabs from './Tabs';
import Glimmer from './Glimmer';

const Comments = React.lazy(() => import('./Comments'));
const Photos = React.lazy(() => import('./Photos'));

function MyComponent() {
const [tab, setTab] = React.useState('photos');

function handleTabSelect(tab) {
setTab(tab);
};

return (
<div>
<Tabs onTabSelect={handleTabSelect} />
<Suspense fallback={<Glimmer />}>
{tab === 'photos' ? <Photos /> : <Comments />}
</Suspense>
</div>
);
}

In this example, if tab gets changed from 'photos' to 'comments' , but Comments suspends, the user will see a glimmer. This makes sense because the user no longer wants to see Photos , the Comments component is not ready to render anything, and React needs to keep the user experience consistent, so it has no choice but to show the Glimmer above.


However, sometimes this user experience is not desirable. In particular, it is sometimes better to show the “old” UI while the new UI is being prepared. You can use the new startTransition API to make React do this:


function handleTabSelect(tab) {
startTransition(() => {
setTab(tab);
});
}

Here, you tell React that setting tab to 'comments' is not an urgent update, but is a transition that may take some time. React will then keep the old UI in place and interactive, and will switch to showing <Comments /> when it is ready. See Transitions for more info.


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, Routes, Route } from 'react-router-dom';

const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));

const App = () => (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</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"));
Is this page useful? Edit this page
Read article
Context – React

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 such usage 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. Such inversion, however, 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 default value 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() . Using this property 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. Using this component 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>
);
}
}

const root = ReactDOM.createRoot(
document.getElementById('root')
);
root.render(<App />);


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>
);
}

const root = ReactDOM.createRoot(
document.getElementById('root')
);
root.render(<App />);


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 (
<MyContext.Provider value={this.state.value}> <Toolbar />
</MyContext.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.


Is this page useful? Edit this page
Read article
Error Boundaries – React

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 <h1>Something went wrong.</h1>; }
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 the catch {} block works in JavaScript.


Live Demo


Check out this example of declaring and using an error boundary.


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 how 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:







Error caught by Error Boundary component





You can also see the filenames and line numbers in the component stack trace. This works by default in Create React App projects:







Error caught by Error Boundary component with line numbers





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 an 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 <h1>Caught an error.</h1> } 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.

Is this page useful? Edit this page
Read article
Forwarding Refs – React

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:



  1. We create a React ref by calling React.createRef and assign it to a ref variable.

  2. We pass our ref down to <FancyButton ref={ref}> by specifying it as a JSX attribute.

  3. React passes the ref to the (props, ref) => ... function inside forwardRef as a second argument.

  4. We forward this ref argument down to <button ref={ref}> by specifying it as a JSX attribute.

  5. 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);
}

Is this page useful? Edit this page
Read article

Still Thinking?
Give us a try!

We embrace agility in everything we do.
Our onboarding process is both simple and meaningful.
We can't wait to welcome you on AiDOOS!