Ruby
Ruby

Reputation: 2909

"Reselect" VS "Memoize-One" with "React and Redux"

I'm trying to use some kind of memoization in my workflow with React, and I'm searching for the best and most importantly the "easiest" solution to integrate with my workflow that includes React and Redux.

I came across many articles talking about memoization in general and some demonstrate the use of "memoize-one" and brace it as the fastest and easiest to get up and running with, and others don't even mention it and talk about "reselect".

I just want to know which is better and easiest and which should I invest in.

Upvotes: 6

Views: 6255

Answers (3)

Andrea Carraro
Andrea Carraro

Reputation: 10419

Both libraries return a function which accepts a given numbers of arguments and returns a value:

getA(arg1, arg2, arg3) // Returns a value

The difference lays in what happens under the hoods when the function is called.

memoize-one

  • collect provided arguments
  • compare arguments with the ones provided in previous call (===)
  • arguments are the same: return cached result
  • arguments are NOT the same: re-evaluate result function and return

reselect

  • collect provided arguments
  • run a set of inputSelectors function providing them with the collected arguments
  • collect inputSelectors return values
  • compare inputSelectors return values with the ones obtained in previous call (===)
  • values are the same: return cached result
  • values are NOT the same: re-evaluate result function and return

Conclusions

memoize-one is a value-based memoize utility: memoization is performed over the value of provided arguments.

reselect adds a further evaluation layer on top of it: memoization is NOT performed over arguments values BUT over the results of a set inputSelectors functions fed with those initial arguments.

It means that reselect selectors are easily composable since each inputSelectors can be another reselect selector.

Upvotes: 19

Carey
Carey

Reputation: 61

I haven't used reselect, but memoize-one works great for me when I want to calculate something from props inside render. This is a great pattern for doing an expensive operation, like mapping a large array, on props that may change over time but also may not change on some re-renders. It ensures an expensive operation used in render is re-computed only when the inputs change. It also avoids having to use lifecycle methods like getDerivedStateFromProps (if it can be calculated from props, it probably shouldn't be on state).

import memoize from 'memoize-one'

class Example extends Component {

  mapList = memoize(
    (list) => list.map(item => ({text: item.text}))
  )

  render() {
    // if this.props.list hasn't changed since the last render
    // memoize-one will re-use the last return value from cache
    const mappedList = this.mapList(this.props.list)

    return (
      ...
    )
  }
}

Keep in mind, in most cases, you’ll want to attach the memoized function to a component instance vs. using a static class variable. This prevents multiple instances of a component from resetting each other’s memoized keys.

Upvotes: 5

Dávid Molnár
Dávid Molnár

Reputation: 11563

I suggest to use reselect, since it was specifically designed to use with React/Redux. memoize-one is more like a general purpose memoization library.

It's really easy to use reselect, it just wraps your selectors:

import { createSelector } from 'reselect';

const shopItemsSelector = state => state.shop.items;

// without reselect
const subtotalSelector = state => {
  const items = shopItemsSelector(state);
  return items.reduce((acc, item) => acc + item.value, 0);
}

// with reselect
const subtotalSelector = createSelector(
  shopItemsSelector, // list the selectors you need
  items => items.reduce((acc, item) => acc + item.value, 0) // the last argument is actual selector
)

Upvotes: 2

Related Questions