Portal And Error Boundaries In React

Introduction

 
In the previous article, we learned about Memo and Refs in React. We also learned forwarding Ref in React. In this article, we will learn about React Portal and Error Boundary and how it can be used in React.
 

Portal

 
A React Portal is a way of binding an element outside of its component hierarchy, in a separate component. The name Portal represents that an element can be set anywhere in the DOM tree that’s outside of the normal React components tree. The concept of Portal is added after version 16.0 in React.
 
React provides an API to create portal named ReactDOM.createPortal() that accepts 2 parameters, the first parameter is an element which needs to be rendered and the second element is the DOM element in which it needs to be rendered. Portals are mostly used for implementing, Tooltip, Modals, Global message notifications, hovercards, chat widgets, and Floating menus. For Portal, we can return strings, numbers, components, React portals or an array of children.
 

Event Bubbling through React Portals

 
As React portal can be anywhere outside of DOM tree but it will act like a React child in all other ways, despite the fact that a child is a portal, it will still exist in the React tree regardless of its position in the DOM tree. So, if we want to trigger any event from the Portal, it will propagate to ancestors in the containing tree, even if those elements are not ancestors of the DOM tree.
 
Let’s look at the demo that will display tooltip using Portal.
  1. import React, { Component } from 'react'    
  2.     
  3. class Tooltip extends Component {    
  4.   constructor(props) {    
  5.     super(props)    
  6.     this.state = { hover: false }    
  7.   }    
  8.       
  9.   handleMouseIn() {    
  10.     this.setState({ hover: true })    
  11.   }    
  12.       
  13.   handleMouseOut() {    
  14.     this.setState({ hover: false })    
  15.   }    
  16.       
  17.   render() {    
  18.     const tooltipStyle = {    
  19.       display: this.state.hover ? 'block' : 'none'    
  20.     }    
  21.         
  22.     return (    
  23.     
  24.       <div>    
  25.         <div onMouseOver={this.handleMouseIn.bind(this)} onMouseOut={this.handleMouseOut.bind(this)}>on hover here we will show the tooltip</div>    
  26.         <div>    
  27.           <div style={tooltipStyle}>this is the tooltip!!</div>    
  28.         </div>    
  29.       </div>    
  30.     );    
  31.   }    
  32. }    
  33.     
  34. export default Tooltip     
Now, use the Tooltip component in the App component.
  1. import React from 'react';    
  2. import logo from './logo.svg';    
  3. import './App.css';    
  4. import Tooltip from "./components/Tooltip"    
  5.     
  6. function App() {    
  7.   return (    
  8.     <div>    
  9.       <header>    
  10.         <img src={logo} className="App-logo" alt="logo" />                  
  11.       </header>          
  12.       <div>    
  13.         <Tooltip>Hello World !</Tooltip>    
  14.       </div>    
  15.     </div>    
  16.   );    
  17. }    
  18.     
  19. export default App;  
The output will be displayed as below.
 
Portal And Error Boundaries In React
Portal And Error Boundaries In React
So, in this way, we can also customize a component for extra functionalities like creating models, Tooltip, etc.
 

Error Boundary

 
In React, there is a concept for Error Boundary that prevents the errors being thrown to the user. So, if any error occurs, this will display a user-friendly view. This Error Boundary component is a component that catches JavaScript errors from their child component trees, log those errors, and display a fallback UI in place of the component tree crashed errors thrown by the application. Error Boundaries catch errors during rendering, in lifecycle methods, and in constructor inside the whole trees. Error Boundaries are created as a class boundary when any one or both of these methods are defined -  static getDerievedStateFromError() or componentDidCatch().
 
The above 2 error methods are used to catch error UI and log error information respectively.
 
static getDerievedStateFromError()
 
This method is invoked after an error is thrown by the child component. It gets the error thrown by the child component as a parameter and it should return the value to update state.
 
The below code is a basic syntax to use Error Boundary.
  1. import React,{Component} from 'react';    
  2.     
  3. class ErrorBoundary extends Component{    
  4.     constructor(props) {    
  5.         super(props)    
  6.         
  7.         this.state = {    
  8.             hasError : false    
  9.         }    
  10.     }    
  11.     
  12.     static getDerivedStateFromError(error){    
  13.         return {hasError:true};    
  14.     }    
  15.     
  16.     render(){    
  17.         if(this.state.hasError){    
  18.             return <h2>Error Occurred</h2>                
  19.         }    
  20.         return this.props.children;    
  21.     }    
  22. }    
  23.     
  24. export default ErrorBoundary    
As the getDerievedFromState() method is called during the render phase just to set the state in React, so it does not involve any side effects. So, for that, we need to use the componentDidCatch() method.
 
componentDidCatch()
 
This method is used to log error information thrown during the getDerievedFromState() method.
 
Syntax - componentDidCatch(error,info)
  1. import React,{Component} from 'react';    
  2.     
  3. class ErrorBoundary extends Component{    
  4.     constructor(props) {    
  5.         super(props)    
  6.         
  7.         this.state = {    
  8.             hasError : false    
  9.         }    
  10.     }    
  11.     
  12.     static getDerivedStateFromError(error){    
  13.         return {hasError:true};    
  14.     }    
  15.     
  16.     componentDidCatch(error,info){    
  17.       // Any reporting Service of custom code to set state    
  18.     }    
  19.         
  20.     render(){    
  21.         if(this.state.hasError){    
  22.             return <h2>Error Occurred</h2>                
  23.         }    
  24.         return this.props.children;    
  25.     }    
  26. }    
  27.     
  28. export default ErrorBoundary   
The lifecycle is invoked when an error is thrown from a child component. It takes 2 parameters.
 
error - The error that was thrown
Info - An object with ComponentStack key containing information about which component threw the error.
 
componentDidCatch() is called during commit phase, so side effects are permitted and used for logging errors. 
 
Some important point to keep in mind while using Error Boundary,
  1. Error boundaries do not catch error in below cases,
  2. Thrown in error boundary itself.
  3. Event handlers
  4. for Async Code
  5. Server Side rendering
  6. Only class components can be error boundaries
  7. Error boundaries work like javascript `catch {}` block, but just for a component.
Let’s see a demo for Error Boundary.
 
ErrorBoundary.js
  1. import React,{Component} from 'react';    
  2.     
  3. class ErrorBoundary extends Component{    
  4.     constructor(props) {    
  5.         super(props)    
  6.         
  7.         this.state = {    
  8.             hasError : false    
  9.         }    
  10.     }      
  11.     static getDerivedStateFromError(error){    
  12.         return {hasError:true};    
  13.     }      
  14.     componentDidCatch(error,info){    
  15.         this.setState({    
  16.             hasError:true    
  17.         })    
  18.     }          
  19.     render(){    
  20.         if(this.state.hasError){    
  21.             return <h2>Error Occured</h2>                
  22.         }    
  23.         return this.props.children;    
  24.     }    
  25. }      
  26. export default ErrorBoundary    
Just change a method name to generate error in Tooltip.js
  1. import React, { Component } from 'react'      
  2. class Tooltip extends Component {    
  3.   constructor(props) {    
  4.     super(props)    
  5.     this.state = { hover: false }    
  6.   }        
  7.   handleMouseIn() {    
  8.     this.setState({ hover: true })    
  9.   }        
  10.   handleMouseOut() {    
  11.     this.setState({ hover: false })    
  12.   }        
  13.   render() {    
  14.     const tooltipStyle = {    
  15.       display: this.state.hover ? 'block' : 'none'    
  16.     }    
  17.     return (      
  18.       <div>    
  19.         <div onMouseOver={this.handleMouseIn.bind(this)} onMouseOut={this.handleMouseOut1.bind(this)}>on hover here we will show the tooltip</div>    
  20.         <div>    
  21.           <div style={tooltipStyle}>this is the tooltip!!</div>    
  22.         </div>    
  23.       </div>    
  24.     );    
  25.   }    
  26. }      
  27. export default Tooltip    
Now in App.js file
  1. import React from 'react';    
  2. import logo from './logo.svg';    
  3. import './App.css';    
  4. import Tooltip from "./components/Tooltip"    
  5. import ErrorBoundary from "./components/ErrorBoundary"    
  6.     
  7. function App() {    
  8.   return (    
  9.     <ErrorBoundary>    
  10.     <div>    
  11.       <header>    
  12.         <img src={logo} className="App-logo" alt="logo" />                  
  13.       </header>          
  14.       <div>    
  15.         <Tooltip>Hello World !</Tooltip>    
  16.       </div>    
  17.     </div>    
  18.     </ErrorBoundary>    
  19.   );    
  20. }    
  21.     
  22. export default App;    
The output will be displayed as below,
 
Portal And Error Boundaries In React
Here you will note a change. After displaying the above screen just after a few seconds error page is displayed again as below,
 
Portal And Error Boundaries In React
 
This is because in development phase Error Boundaries do not override error overlay. Which may not happen in the production phase. To resolve this issue you can add below code in your CSS file.
  1. iframe {    
  2.   display: none;    
  3. }  
Then, the text or image you want to display using the error boundary will remain on browser's screen.
 

Summary

 
In this article, we have learned about Portals and Error Boundary in React. And how it can be implemented in React Js. You can download source code attached along with this article. In the next article, we will learn in detail about the concept and usage of Higher-Order Components (HOCs) in React.
 
Next in this series >> Higher Order Component in React