Performance issues over React App

This is a (draft) list of all the code related issues related to React performance.

This is a draft! Published for self-reference and for whoever understands without the extra text wrapping. Sorry if it lacks the slickness and elegance on this post. In this time period, and for its goal – it’s just not worth it.

Measure. Don’t tune for speed until you’ve measured, and even then don’t unless one part of the code overwhelms the rest.

5 Rules of programming. Rob Pike’s

Remove inline functions

Demo: See the difference on the log of the two different buttons:

const SubApp = (props)=>{
  console.log('Sub re-render');
  return  <button {...props}>{props.title}</button>

}

const App = ()=>{
  console.log('App re-render');
  const [counter,setCounter] = React.useState(0);
  const stateFunction = React.useCallback(()=>{
    setCounter(counter + 1);
    console.log('State function');
  },[]);

  return  <p>
    <SubApp title="Inline function" onClick={() => { setCounter(counter + 1); return console.log('Inline function')}}  />
    <SubApp title="State function" onClick={stateFunction}  />
    </p>
}

This decreased the memory footprint from 1.5Gb to 800Mb 😄

Journey of Improving React App Performance by 10x. Mayank Sharma

And you can see the magic in the log…

React also knows to update only the properties that changed.

React Reconciliation

Memoize React Components and function

React.memo, useMemo, useCallback …

  • Pure functional component
  • renders often
  • re-renders with the same props
  • Medium to high UI elements

Avoid Object Literals

Object literals don’t have a persistent memory space, so your component will need to allocate a new location in memory whenever the component re-renders

Conditional rendering

const SomeComponent = ({someValue})=>{
  ...
  ...

  if(!someValue) return null;

  return  <div>
      ...
      ...
    </div>

}

This decreased the memory footprint from 500Mb to 150Mb. 😄

Journey of Improving React App Performance by 10x. Mayank Sharma

Throttling and Debouncing Events

  const search = debounce(e => {
    setSearch({ value: e.target.value });
  }, 1000);
  
  return  <p>
      <input type="text" onChange={search} />
    </p>

Remove unnecessary awaits

This decreased the initial page load time and other pages by 30%.

Journey of Improving React App Performance by 10x. Mayank Sharma

React.Fragments

Reduce the amount of HTML element by using React.Fragments

return <>
    <CompOne />
    <CompTwo />
</>

Virtualize long lists

Efficiently rendering large lists by rendering only enough to fill the viewport and not a large data set. This helps address some common performance bottlenecks by reducing the amount of work required to render the initial view.

Awesome React libraries have been built for this, there is the react-window and react-virtuaized

Code Splitting

Change …

import { add } from './math';

import("./math").then(math => {
    ....
}

Lazy loading

Component lazy loading:

import OtherComponent from './OtherComponent';

const OtherComponent = React.lazy(() => import('./OtherComponent')); 
const  MyComponent() {   
    return (     
        <div>       
            <Suspense fallback={<div>Loading...</div>} /> 
                <OtherComponent />      
            </Suspense>     
        </div>   
    ); 
}

Or rout base lazy loading

ReactDom.render(<React.StrictMode><App /></React.StrictMode>, document.getElementById('root'))

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

Immutable Data Structures

Children recursing

Adding a new element at the bottom of the list will add one element to the DOM. Adding something in the middle will recreate all the elements in the list.

Avoid using Index as Key

Avoid spreading props

Using spread to spread props inside an JSX element can create unknown and unwanted HTML attributes.

Other none code related:

  • Multiple Chunk Files
  • Production Mode Flag in Webpack
  • Dependency optimization
  • Use CDN
  • Web Workers for CPU Extensive Tasks

Resources: