Skip to content

Selector dependencies using this #14

Open
@acjay

Description

@acjay

Right now, RRC provides no real help for the selector story. In our use case at Artsy, we have a great deal of selectors, which depend on the state and on each other. However, writing these selectors as functions from state to a derived value is a bit awkward, composing them is even more so, and using something like reselect for memoization is so awkward that we don't even bother.

In the example, we have:

import { PropTypes } from 'react'

export const selectedReddit = state => state.selectedReddit
selectedReddit.propType = PropTypes.string.isRequired

export const postsByReddit = state => state.postsByReddit
postsByReddit.propType = PropTypes.object.isRequired

export const posts = state => {
  const p = state.postsByReddit[selectedReddit(state)]
  return p && p.items ? p.items : []
}
posts.propType = PropTypes.array.isRequired

export const isFetching = state => {
  const posts = state.postsByReddit[selectedReddit(state)]
  return posts ? posts.isFetching : true
}
isFetching.propType = PropTypes.bool.isRequired

export const lastUpdated = state => {
  const posts = state.postsByReddit[selectedReddit(state)]
  return posts && posts.lastUpdated
}
lastUpdated.propType = PropTypes.number

The functional composition works, but it's also pretty noisy. A better API might be:

export class Selectors {
  get posts() {
    const p = this.postsByReddit[this.selectedReddit]
    return p && p.items ? p.items : []
  }

  get isFetching() {
    const posts = this.postsByReddit[this.selectedReddit]
    return posts ? posts.isFetching : true
  }

  get lastUpdated() {
    const posts = this.postsByReddit[this.selectedReddit]
    return posts && posts.lastUpdated
  }
}

Selectors.propTypes = {
  selectedReddit: PropTypes.string.isRequired,
  postsByReddit: PropTypes.object.isRequired,
  posts: PropTypes.array.isRequired,
  isFetching: PropTypes.bool.isRequired,
  lastUpdated: PropTypes.number
};

This feels much more direct and intuitive. Library magic would make sure that the Redux state is accessible via this.

Selectors would also become lazy, instead of eagerly computed. It may also be possible to rely on said library magic to opt selectors into memoization.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions