New advanced features of Reactjs 16+ version
There are many new advanced features introduce by Facebook in Reactjs 16+ version.
1. Code-Splitting
2. Error Boundaries
3. Context
4. Profiler
5. Static Type Checking
6. Fragments
7. Strict Mode
8. Portals
9. Forwarding Refs
10. Web Components
Code-Splitting
First question comes in mind why do we need code-splitting. Bundling is a great and web application use bundling mechanism. As your app grows, your bundle will grow too. You need to take care about bundle side to avoid to takes long time to load app.
In general you can split your bundle by using webpack or other tool. But reactjs 16 provides many ways to code-split into bundles.
React.lazy
React.lazy function lets you render a dynamic import as a regular component. Imported component will render on demand.
import React from "react"; //before import TestComponent from "./TestComponent"; //After const TestComponent = React.lazy(() => import('./TestComponent'));
React.lazy function must return Promise which resolves to a module with a default export containing a React component. Lazy component should render inside Suspense component.
import React,{Suspense} from "react"; //normal import import HeaderComponent from "./HeaderComponent"; //dynamic import, lazy import must be import in the end const TestComponent = React.lazy(() => import('./TestComponent')); function MyComponent() { return ( <div> <Suspense fallback={<div>Loading...</div>}> <HeaderComponent /> <TestComponent/> </Suspense> </div> ); }
In the Suspense component you can use fallback to display any message during loading the component.You can also use you custom component as a fallback.
Note: make sure all the dynamic/lazy import should be import after normal imports otherwise you will compile error. React.lazy and Suspense not yet available for server side rendering. If you want to code split server side, use Loadable Component as reactjs recommendation.
Route-based code splitting
In single page app web page render based on routing, you can split code in routing by using React.lazy function. Your app code will split into separate bundles based on app page and page will load into browser on demand through routing. It helps to load app very fast and improve the app performance.
routes.js
import React, { Suspense, lazy } from 'react'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; const HomeComponent = lazy(() => import('./HomeComponent')); const AboutComponent = lazy(() => import('./AboutComponent')); const App = () => ( <Router> <Suspense fallback={<div>Loading...</div>}> <Switch> <Route exact path="/" component={HomeComponent}/> <Route path="/about" component={AboutComponent}/> </Switch> </Suspense> </Router> );
Error Boundaries
Error boundary is used to handle run time front-end error and display meaningful message to user. You can create a number of error boundaries according to requirement and you can log your error easily in error boundary component.
MyErrorBoundary.js
import React,{Component} from "react"; import {logError} from "./logService"; class MyErrorBoundary 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 logError(error, errorInfo); } render() { if (this.state.hasError) { // You can render any custom fallback UI return <h1>Something went wrong.</h1>; } return this.props.children; } }
MyComponent.js
import React,{Suspense} from "react"; //normal import import HeaderComponent from "./HeaderComponent"; import MyErrorBoundary from "./MyErrorBoundary"; //dynamic import, lazy import must be import in the end const TestComponent = React.lazy(() => import('./TestComponent')); function MyComponent() { return ( <div> <MyErrorBoundary> <Suspense fallback={<div>Loading...</div>}> <HeaderComponent /> <TestComponent/> </Suspense> </MyErrorBoundary> </div> ); }
Context
Context is used to pass the data through the component tree without having to pass props down manually at every level.
In general React app, data is passed top-down (parent to child) via props, but this can be cumbersome for certain types of props i.e. UI theme, locale preferences etc that can be required in many components in application. Context solve this issue by using context api createContext to pass data.
First you should create context object by using context api createContext and use provider to pass the data and finally get the data in component by using consumer.
import React,{createContext} from "react"; // Create a context for the current theme (with "dark" as the default). const ThemeContext = createContext('dark'); 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 "light" as the current value. return ( <ThemeContext.Provider value="light"> <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 { render() { return( <ThemeContext.Consumer> {value=> <Button theme={value} />} </ThemeContext.Consumer> ) } }
Profiler
The Profiler is used to measures how React application renders and what the cost of rendering. The purpose of Profiler is to help to identify the parts of application that are slow and benefit from optimization such as memoization.
Profiler can be added anywhere in react tree to measure the cost of rendering that part of tree. You need to pass two props an id (string) and onRender callback function which React call any time a component within the tree commits and update. You can many profilers as much as you require.
Note: Profiler adds some overhead, so it is disabled in production build.
render( <App> <Profiler id="nav" onRender={callback}> <Navigation {...props} /> </Profiler> <Profiler id="main" onRender={callback}> <Main {...props} /> </Profiler> </App> );
Static Type Checking
Static type checking is used to identify certain types of problem before you ever run your code. To solve types problems reactjs suggest to use Flow or TypeScript instead of PropsTypes for large code base.
Fragments
As reactjs render single element so you need to wrap multiple elements into single element. Fragment wrap list of children without adding extra node to the DOM. Major problem comes when you want to group multiple components like Table component which have divide into multiple component Column and Row component. It cause the issue with adding extra node into dom. But Fragment solve the issue , Fragment can be used as <React.Fragment>children</React.Fragment> or <>children</>.
render() { return ( <React.Fragment> <ChildA /> <ChildB /> <ChildC /> </React.Fragment> ); } //or render() { return ( <> <ChildA /> <ChildB /> <ChildC /> </> ); }
Strict Mode
Strict Mode is a tool which is used to highlight the potential problems in the application. It does not render any UI. It activates additional checks warnings for its descendants.
Strict Mode help to identify below problems
- Detect legacy context API
- Identify components with unsafe lifecycles
- Detecting unexpected side effects
- Warning about deprecated findDOMNode usage
Note: strict mode check are run in development mode only, they don't impact in production mode.
import React from 'react'; function ExampleApplication() { return ( <div> <Header /> <React.StrictMode> <div> <ComponentX /> <ComponentY /> </div> </React.StrictMode> <Footer /> </div> ); }
Portals
Portals is the first-class way to render children into DOM node that exits outside the DOM hierarchy of the parent component. There are some case where you can use Portals like tooltip and modal etc.
createPortal function is used to create portal which takes two parameters child and container.
<div id="app"></div> <div id="modal"></div>
// These two containers are siblings in the DOM const appRoot = document.getElementById('app'); const modalRoot = document.getElementById('modal'); // Let's create a Modal component that is an abstraction around // the portal API. class Modal extends React.Component { constructor(props) { super(props); // Create a div that we'll render the modal into. Because each // Modal component has its own element, we can render multiple // modal components into the modal container. this.el = document.createElement('div'); } componentDidMount() { // Append the element into the DOM on mount. We'll render // into the modal container element (see the HTML tab). modalRoot.appendChild(this.el); } componentWillUnmount() { // Remove the element from the DOM when we unmount modalRoot.removeChild(this.el); } render() { // Use a portal to render the children into the element return ReactDOM.createPortal( // Any valid React child: JSX, strings, arrays, etc. this.props.children, // A DOM element this.el, ); } } // The Modal component is a normal React component, so we can // render it wherever we like without needing to know that it's // implemented with portals. class App extends React.Component { constructor(props) { super(props); this.state = {showModal: false}; this.handleShow = this.handleShow.bind(this); this.handleHide = this.handleHide.bind(this); } handleShow() { this.setState({showModal: true}); } handleHide() { this.setState({showModal: false}); } render() { // Show a Modal on click. // (In a real app, don't forget to use ARIA attributes // for accessibility!) const modal = this.state.showModal ? ( <Modal> <div className="modal"> <div> With a portal, we can render content into a different part of the DOM, as if it were any other React child. </div> This is being rendered inside the #modal-container div. <button onClick={this.handleHide}>Hide modal</button> </div> </Modal> ) : null; return ( <div className="app"> This div has overflow: hidden. <button onClick={this.handleShow}>Show modal</button> {modal} </div> ); } } ReactDOM.render(<App />, appRoot);
Forwarding Refs
Forwarding refs is used for automatically passing a ref through a component to one of its children. It can be useful some kinds of components, especially in reusable components.
createRef function is used to create ref and forwardRef function is used to forward ref.
const FancyButtonComponent = React.forwardRef((props, ref) => ( <button ref={ref} className="fancy"> {props.children} </button> )); // You can now get a ref directly to the DOM button: const ref = React.createRef(); <FancyButtonComponent ref={ref}>Click me!</FancyButtonComponent>;
Web Components
Web components provide encapsulation for reusable components, while React provides a declarative library that keep in sync with your data. Developer is free to use React in your web components or web components in React or both.
Web Component is very useful for micro front-end architecture, no matter in which library or framework your application build. Expose your application as a web component and use it as a html tag. Let suppose there are four micro applications , two app build by using React and other two with Vue or angular. In this case expose your application as web component and integrate with any application.
class AdvanceSearch 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', AdvanceSearch);
Comments
Post a Comment
Thanks for visiting blog. Have a good day.