Optimizing React Performance with Stateless Components

This story is about stateless components. This means components that don’t have any this.state = { ... } calls in them. They only deal with incoming “props” and sub-components.

First, the Super Basics

import React, { Component } from 'react'

class User extends Component {
  render() {
    const { name, highlighted, userSelected } = this.props
    console.log('Hey User is being rendered for', [name, highlighted])
    return <div>
      <h3
        style={{fontStyle: highlighted ? 'italic' : 'normal'}}
        onClick={event => {
          userSelected()
        }}
        >{name}</h3>
    </div>
  }
}

Yay! It works. It’s really basic but sets up the example.

Things to note:

  • It’s stateless. No this.state = { ... }.
  • The console.log is there so you can get insight it being used. In particular, when you do performance optimization, you’ll want to avoid unnecessary re-renders when the props haven’t actually changed.
  • The event handler there is “inline”. This is convenient syntax because the code for it is close to the element it handles, plus this syntax means you don’t have to do any .bind(this) sit-ups.
  • With inline functions like that, there is a small performance penalty since the function has to be created on every render. More about this point later.

It’s a Presentational Component

We realize now that the component above is not only stateless, it’s actually what Dan Abramov calls a presentational component. It’s just a name but basically, it’s lightweight, yields some HTML/DOM, and doesn’t mess around with any state-data.

So we can make it a function! Yay! That not only feels “hip”, but it also makes it less scary because it’s easier to reason about. It gets inputs and, independent of the environment, always returns the same output. Granted, it “calls back” since one of the props is a callable function.

So, let’s re-write it:

const User = ({ name, highlighted, userSelected }) => {
  console.log('Hey User is being rendered for', [name, highlighted])
  return <div>
    <h3
      style={{fontStyle: highlighted ? 'italic' : 'normal'}}
      onClick={event => {
        userSelected()
      }}>{name}</h3>
  </div>
}

Doesn’t that feel great? It feels like pure JavaScript and something you can write without having to think about the framework you’re using.

It Keeps Re-rendering, They Say 🙁

Suppose our little User is used in a component that has state which changes over time. But the state doesn’t affect our component. For example, something like this:

import React, { Component } from 'react'

class Users extends Component {
  constructor(props) {
    super(props)
    this.state = {
      otherData: null,
      users: [{name: 'John Doe', highlighted: false}]
    }
  }

  async componentDidMount() {
    try {
      let response = await fetch('https://api.github.com')
      let data = await response.json()
      this.setState({otherData: data})
    } catch(err) {
      throw err
    }
  }

  toggleUserHighlight(user) {
    this.setState(prevState => {
      users: prevState.users.map(u => {
        if (u.name === user.name) {
          u.highlighted = !u.highlighted
        }
        return u
      })
    })
  }

  render() {
    return <div>
      <h1>Users</h1>
      {
        this.state.users.map(user => {
          return <User
            name={user.name}
            highlighted={user.highlighted}
            userSelected={() => {
              this.toggleUserHighlight(user)
            }}/>
         })
      }
    </div>
  }
}

Continue reading %Optimizing React Performance with Stateless Components%


Source: Sitepoint