composeSelectors(...selectors)

Composing selectors means feed the value from one selector into another selector. composeSelectors is based on redux's compose function. If you don't use composeSelectors, redux is not a required peer dependency.

Note: Comfy redux-selectors composes selectors left to right. Redux's compose function goes right to left.

Basic usage

composeSelectors accepts a list of selectors as arguments. The result of each selector is "fed forward" into the next selector. Typically compose functions run right-to-left. However, redux-selectors composes left-to-right in order to make the composed functions more readable as a sentence.

Notice that you can supply a mix of path and functional selectors. Each selector is passed through createStateSelector before being executed.

import { composeSelectors } from '@comfy/redux-selectors'

const selectApple = composeSelectors(
  'department.produce',
  state => state.fruit,
  'apple'
)

// ---

const state = {
  department: {
    produce: {
      fruit: {
        apple: 1
      }  
    }
  }
}

selectApple(state) // => 1

Example usage: selectRoot

Commonly, your selectors are dependent on the location of the rootReducer in the state. Meaning, typically you are writing selectors that read values from a specific part of the state, managed by a specific reducer. Comfy redux-selectors provides composeSelectors specifically to facilitate composing child selectors with a selectRoot function.

Using selectRoot is a huge benefit for refactoring code. This pattern enables you to change only a single function in the event that a reducer is relocated in the state.

import { createSelector, composeSelectors } from '@comfy/redux-selectors'

export const selectRoot = createSelector('department.produce') // <-- root selector
export const selectFruit = composeSelectors(selectRoot, 'fruit') // <-- composes left to right
export const selectApples = composeSelectors(selectFruit, 'apples') // <-- compose a composed selector
export const selectOranges = composeSelectors(selectFruit, 'oranges')

// ---

const state = {
  department: {
    produce: {
      fruit: { apples: 1, oranges: 2 }
    }
  }
}

selectOranges(state) // => 2

Advanced Usage

This example shows an advanced usage of selector composition to retrieve entities from a collection. This covers a common use-case where you need to select from an array of objects by ID.

Both selectAppleById and selectApplesOfSize demonstrate selectively memoizing portions of your selectors. In this case, there is no need to memoize selectApples. The result of selectApples can be considered as immutable as state.

You can also notice the usage of "object selectors" that expect to read from an object instead of the whole state. Below you can see that selectSize will blindly read the size from any object it receives. You can see it used in both selectApplesOfSize and selectSizeFromId to read the size of an apple.

import { createSelector, withOptions, composeSelectors, memoizeSelector } from '@comfy/redux-selectors'

const selectRoot = createSelector('department.produce')
export const selectFruit = composeSelectors(selectRoot, 'fruit')
const selectApples = composeSelectors(selectFruit, 'apples')
const selectAppleById = withOptions(id => composeSelectors(
  selectApples,
  memoizeSelector(apples => apples.find(apple => selectId(apple) === id))  
))
const selectApplesOfSize = withOptions(size => composeSelectors(
  selectApples,
  memoizeSelector(apples => apples.filter(apple => selectSize(apple) === size))  
))
const selectSizeFromId = withOptions(id => composeSelectors(
  selectAppleById(id),
  selectSize
))

// object selectors
const selectId = createSelector('id')
const selectSize = createSelector('attributes.size')

const state = {
  department: {
    produce: {
      fruit: {
        apples: [
          { id: 1, attributes: { size: 'big' } }
        ]
      }  
    }
  }
}

const apple1 = selectAppleById(1)(state)
const bigApples = selectApplesOfSize('big')(state)

apple1 === bigApples[0] // => true
selectSize(apple1) // => big
selectSizeFromId(1)(state) // => big

results matching ""

    powered by

    No results matching ""