React Render Performance

Tyler Graf

Web Dev

Tree Team

React Render Lifecycle

2. Commit

Make diff changes appear in the DOM

1. Render

Run a diff for all components.

Phases

Virtual DOM Diffing

import React, { Component } from "react";

export default class Counter extends Component {
  constructor(props) {
    super(props);
  }
  
  shouldComponentUpdate(oldProps, newProps) {}
  
  render({ currentCount, handleAdd, handleSubtract }) {
    return (
      <div>
        <HeaderBlock size="lg" heading="Counter Example" />
        <p>Count: {currentCount}</p>
        <IconButton onClick={handleAdd} Icon={ContentAdd} />
        <IconButton onClick={handleSubtract} Icon={ContentRemove} />
      </div>
    );
  }
  
  componentWillUnmount() {}
  
  componentDidUpdate() {}
  
  componentDidMount() {}
}

Class Component

import React, { Component } from "react";

export default class Counter extends Component {
  constructor(props) {
    super(props);
  }
  
  shouldComponentUpdate(oldProps, newProps) {}
  
  render({ currentCount, handleAdd, handleSubtract }) {
    return (
      <div>
        <HeaderBlock size="lg" heading="Counter Example" />
        <p>Count: {currentCount}</p>
        <IconButton onClick={handleAdd} Icon={ContentAdd} />
        <IconButton onClick={handleSubtract} Icon={ContentRemove} />
      </div>
    );
  }
  
  componentWillUnmount() {}
  
  componentDidUpdate() {}
  
  componentDidMount() {}
}

Functional Component

import React, { Component } from "react";

export default function Counter({ currentCount, handleAdd, handleSubtract }) {
  const coolCss = css`
    display: flex;
  `
  
  return (
    <div css={coolCss}>
      <HeaderBlock size="lg" heading="Counter Example" />
      <p>Count: {currentCount}</p>
      <IconButton onClick={handleAdd} Icon={ContentAdd} />
      <IconButton onClick={handleSubtract} Icon={ContentRemove} />
    </div>
  );
}
import React, { Component } from "react";

const coolCss = css`
  display: flex;
`

export default function Counter({ currentCount, handleAdd, handleSubtract }) {
  return (
    <div css={coolCss}>
      <HeaderBlock size="lg" heading="Counter Example" />
      <p>Count: {currentCount}</p>
      <IconButton onClick={handleAdd} Icon={ContentAdd} />
      <IconButton onClick={handleSubtract} Icon={ContentRemove} />
    </div>
  );
}
import React, { Component } from "react";

export default class Counter extends Component {
  constructor(props) {
    super(props);
  }
  
  shouldComponentUpdate(oldProps, newProps) {
    return oldProps.currentCount === newProps.currentCount
  }
  
  render({ currentCount, handleAdd, handleSubtract }) {
    return (
      <div>
        <HeaderBlock size="lg" heading="Counter Example" />
        <p>Count: {currentCount}</p>
        <IconButton onClick={handleAdd} Icon={ContentAdd} />
        <IconButton onClick={handleSubtract} Icon={ContentRemove} />
      </div>
    );
  }
  
  componentWillUnmount() {}
  
  componentDidUpdate() {}
  
  componentDidMount() {}
}

Conditional Re-rendering

Conclusion:

Move to Class Components

React perf functions

React.memo

React.useCallback

React.useMemo

React.memo

import React from 'react'
import { IconButton, HeaderBlock } from '@fs/zion-ui'
import { ContentAdd, ContentRemove } from '@fs/zion-icon'

export default function Counter({ currentCount, handleAdd, handleSubtract }) {
  return (
    <div>
      <HeaderBlock size="lg" heading="Counter Example" />
      <p>Count: {currentCount}</p>
      <IconButton onClick={handleAdd} Icon={ContentAdd} />
      <IconButton onClick={handleSubtract} Icon={ContentRemove} />
    </div>
  )
}
import React, { memo } from 'react'
import { IconButton, HeaderBlock } from '@fs/zion-ui'
import { ContentAdd, ContentRemove } from '@fs/zion-icon'

function Counter({ currentCount, handleAdd, handleSubtract }) {
  return (
    <div>
      <HeaderBlock size="lg" heading="Counter Example" />
      <p>Count: {currentCount}</p>
      <IconButton onClick={handleAdd} Icon={ContentAdd} />
      <IconButton onClick={handleSubtract} Icon={ContentRemove} />
    </div>
  )
}

export default memo(Counter)
import React, { memo } from 'react'
import { IconButton, HeaderBlock } from '@fs/zion-ui'
import { ContentAdd, ContentRemove } from '@fs/zion-icon'

function Counter({ currentCount, handleAdd, handleSubtract }) {
  return (
    <div>
      <HeaderBlock size="lg" heading="Counter Example" />
      <p>Count: {currentCount}</p>
      <IconButton onClick={handleAdd} Icon={ContentAdd} />
      <IconButton onClick={handleSubtract} Icon={ContentRemove} />
    </div>
  )
}

export default memo(Counter, (oldProps, newProps)=>{
  return oldProps.currentCount === newProps.currentCount
})

Used for memoizing components

React.useCallback

import React, { memo, useState } from 'react'
import { IconButton, HeaderBlock } from '@fs/zion-ui'
import { ContentAdd, ContentRemove } from '@fs/zion-icon'

function Counter({ handleSubtract }) {
  const [currentCount, setCurrentCount] = useState(0)
  
  const handleAdd = ()=>{
    setCurrentCount(oldCount=>oldCount + 1)
  }
  
  return (
    <div>
      <HeaderBlock size="lg" heading="Counter Example" />
      <p>Count: {currentCount}</p>
      <IconButton onClick={handleAdd} Icon={ContentAdd} />
      <IconButton onClick={handleSubtract} Icon={ContentRemove} />
    </div>
  )
}

export default memo(Counter)
import React, { memo, useState, useCallback } from 'react'
import { IconButton, HeaderBlock } from '@fs/zion-ui'
import { ContentAdd, ContentRemove } from '@fs/zion-icon'

function Counter({ handleSubtract }) {
  const [currentCount, setCurrentCount] = useState(0)
  
  const handleAdd = useCallback(()=>{
    setCurrentCount(oldCount=>oldCount + 1)
  }, [ setCurrentCount ])
  
  return (
    <div>
      <HeaderBlock size="lg" heading="Counter Example" />
      <p>Count: {currentCount}</p>
      <IconButton onClick={handleAdd} Icon={ContentAdd} />
      <IconButton onClick={handleSubtract} Icon={ContentRemove} />
    </div>
  )
}

export default memo(Counter)

Used for memoizing functions

React.useMemo

import React, { memo, useCallback, useMemo } from 'react'
import { IconButton, HeaderBlock } from '@fs/zion-ui'
import { ContentAdd, ContentRemove } from '@fs/zion-icon'

function Counter({ currentCount, handleSubtract }) {

  const handleAdd = useCallback(()=>{
    console.log('add')
  },[])
  
  const sinValue = useMemo(() => Math.sin(currentCount),[currentCount])
  
  return (
    <div>
      <HeaderBlock size="lg" heading="Counter Example" />
      <p>Count: {currentCount}</p>
      <p>Sin Value: {sinValue}</p>
      <IconButton onClick={handleAdd} Icon={ContentAdd} />
      <IconButton onClick={handleSubtract} Icon={ContentRemove} />
    </div>
  )
}

export default memo(Counter)
import React, { memo, useCallback } from 'react'
import { IconButton, HeaderBlock } from '@fs/zion-ui'
import { ContentAdd, ContentRemove } from '@fs/zion-icon'

function Counter({ currentCount, handleSubtract }) {

  const handleAdd = useCallback(()=>{
    console.log('add')
  },[])
  
  const sinValue = Math.sin(currentCount)
  
  return (
    <div>
      <HeaderBlock size="lg" heading="Counter Example" />
      <p>Count: {currentCount}</p>
      <p>Sin Value: {sinValue}</p>
      <IconButton onClick={handleAdd} Icon={ContentAdd} />
      <IconButton onClick={handleSubtract} Icon={ContentRemove} />
    </div>
  )
}

export default memo(Counter)

Used for memoizing values

React dev tools extension

Demo

React Render Performance

By Tyler Graf

React Render Performance

  • 679