npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

re-select

v0.5.0

Published

Memoized selector library

Downloads

49

Readme

re-select

Memoized selector library

Travis branch npm

The motivation behind this library is to improve reselect usage to be more resilient and concise. By using the new way to construct selectors, you should be able to write selectors that are easier to combine with.

/* selectors.js
**
** You never call createSelector in your `selectors.js`
** import { createSelector } from 'reselect'
*/

const shopItemsSelector = state => state.shop.items
const taxPercentSelector = state => state.shop.taxPercent

// Notice how to use an array structure to describe a selector
const subtotalSelector = [
  shopItemsSelector,
  items => items.reduce((acc, item) => acc + item.value, 0)
]

const taxSelector = [
  [subtotalSelector, taxPercentSelector],
  (subtotal, taxPercent) => subtotal * (taxPercent / 100)
]

let exampleState = {
  shop: {
    taxPercent: 8,
    items: [
      { name: 'apple', value: 1.20 },
      { name: 'orange', value: 0.95 },
    ]
  }
}

// container.js
// On your view layer where the selectors actually get called
import createSelector from 're-select';

connect(createSelector({
  subtotal: subtotalSelector, // 2.15
  tax:      taxSelector,      // 0.172
}))

Installation

npm install re-select

Examples

This introduction will assume you have a basic understanding of reselect. The major difference between re-select and reselect is how you describe/combine a selector.

const getVisibilityFilter = (state) => state.visibilityFilter
const getTodos = (state) => state.todos

/*
const getVisibleTodosFilteredByKeyword = createSelector(
  [ getVisibleTodos, getKeyword ],
  (visibleTodos, keyword) => visibleTodos.filter(
    todo => todo.text.includes(keyword)
  )
)
*/

const filteredVisibleTodosSelector = [
  [ getVisibleTodos, getKeyword ],
  (visibleTodos, keyword) => visibleTodos.filter(
    todo => todo.text.includes(keyword)
  )
]

A very common selector shown in the example above. Instead of calling createSelector to create a selector function, you construct an array structure to describe a selector.

Let's take a closer look at how it works.

The selectors consisted of two parts. The first element is an array of functions, each of which takes the store as input. The second element is a plain function, it takes the value of selectors in the first element as input. So the first argument it takes will be the result of getVisibleTodos and the second will be getKeyword. The Values of each element are cached so if the values of one element are the same as previous the following element will not get called and return the previously computed value. In this example, the second element function will not run until the result of getVisibleTodos or getKeyword changed.

Nested Selector

On the previous example, all input selectors are functions. But they don't have to be.

const todoAuthorSelector = [
  [filteredVisibleTodosSelector],
  todos => todos.map(todo => todo.author)
]

A valid selector description can be a function, an array or a plain object(we'll see it later).

Multiple Pipeline Selector

Let's implement the todoAuthorSelector without nested selectors this time.

const todoAuthorSelector = [
  [ getVisibleTodos, getKeyword ],
  (visibleTodos, keyword) => visibleTodos.filter(
    todo => todo.text.includes(keyword)
  ),
  todos => todos.map(todo => todo.author)
]

You can have even more element in a selector. Like what we have known, each element is memorized and each element takes the previous as input. You should also notice the second element have not been wrapped in []. It's fine, [] is optional when there is only one selector that is not an array.

Structured Selector

When working on a react/redux project, it's a common pattern that selecting data from the redux store and passing it as props to a component. A selector might look like this:

const usernameSelector = state => state.user.name
const postsSelector = state => state.posts

connect(createSelector([
  [usernameSelector, postsSelector],
  (username, posts) => ({
    username,
    posts,
  })
]))

It is when structured selectors come into play. Structured selectors are objects whose properties are a selector. A structured selector equivalent to above can be:

connect(createSelector({
  username: usernameSelector,
  posts: postsSelector,
}))

API

createSelector: selector => memoizedFunction

Takes one selector, return a memoized function. A selector can be a function, an array or a plain object. It determines if the value has changed using reference equality(===).

createMemoizor: equalityCheck => function => memoizedFunction

Passing in an equalityCheck function, return a function that transforms a function to the memoized version.

createSelectorCreator: memoize => createSelector

createSelectorCreator takes a memoize function as input and returns a customized version of createSelector.

Here is an example for using Immutable.is as equalityCheck

import { is } from 'immutable'
import { createSelectorCreator, createMemoizor } from 're-select'

const createImmutableSelector = createSelectorCreator(createMemoizor(is))

License

MIT