Skip to content

Instantly share code, notes, and snippets.

@jonidelv
Last active March 11, 2023 17:14
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonidelv/6bc6e3f4d30b4b23861734afccec31d6 to your computer and use it in GitHub Desktop.
Save jonidelv/6bc6e3f4d30b4b23861734afccec31d6 to your computer and use it in GitHub Desktop.
Computed Properties in React

Computed Properties in React

Achieving Computed Properties the right way


React does not have computed properties out of the box like others frameworks do (Ember, Vue, etc.) so, how can we achieve this behaviour the right way ? The most common practice is to "compute" things in the render method if is a class component or just in the body if is a function component.

Problem

The computation is beeing done on every render, meaning that is generating a new variable even if the values that need to be computed didn't change. Plus if we are passing this as a prop to a child component and is not a primitive type (string, number or boolean) the child will re-render thinking that is a new value and this can cause performance issues.

Solution

Extract Computation to a function and use memoization to prevent from beeing call if the arguments didn't change, this will give us performance gains if we are doing expensive computations like big lists.

Examples

Class component

import React from 'react'
import memoize from 'lodash/memoize'
import MenuItem from './MenuItem'

class RenderSuggestion extends React.Component {

  renderSuggestionStyles = (suggestionValue) => ({ pointerEvents: suggestionValue ? 'all' : 'none' })
  renderSuggestionStylesMemo = memoize(this.renderSuggestionStyles)

  render(){
    const { suggestion, ...other } = this.props
    return (
      <MenuItem
        {...other}
        style={this.renderSuggestionStylesMemo(suggestion.value + 1)}
      />
    )
  }
}

Function component

import React from 'react'
import memoize from 'lodash/memoize'
import MenuItem from './MenuItem'

const renderSuggestionStyles = suggestionValue => ({ pointerEvents: suggestionValue ? 'all' : 'none' })
const renderSuggestionStylesMemo = memoize(renderSuggestionStyles)

function RenderSuggestion({ suggestion, ...other }) {
  return (
    <MenuItem
      {...other}
      style={renderSuggestionStylesMemo(suggestion.value + 1)}
    />
  )
}

Here if we wouldn't use a computed property the right way (without memoization) the child component (MenuItem) would re-render unnecessary when props change.

Reselect

Another cool way of fixing this problem is using reselect

import React from 'react'
import { createSelector } from "reselect";
import MenuItem from './MenuItem'

class RenderSuggestion extends React.Component {

  renderSuggestionStyles = createSelector(
     (suggestionValue) => ({ pointerEvents: suggestionValue ? 'all' : 'none' })
  )

  render(){
    const { suggestion, ...other } = this.props
    return (
      <MenuItem
        {...other}
        style={this.renderSuggestionStyles(suggestion.value + 1)}
      />
    )
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment