Skip to main content

createStructuredSelector

A convenience function that simplifies returning an object made up of selector results.

Parameters

NameDescription
inputSelectorsObjectA key value pair consisting of input selectors.
selectorCreator?A custom selector creator function. It defaults to createSelector.

Returns

A memoized structured selector.

Type Parameters

NameDescription
InputSelectorsObjectThe shape of the input selectors object.
MemoizeFunctionThe type of the memoize function that is used to create the structured selector. It defaults to lruMemoize.
ArgsMemoizeFunctionThe type of the of the memoize function that is used to memoize the arguments passed into the generated structured selector. It defaults to lruMemoize.

Examples

Modern Use Case

createStructuredSelector/modernUseCase.ts
import { createSelector, createStructuredSelector } from 'reselect'

export interface RootState {
todos: {
id: number
completed: boolean
title: string
description: string
}[]
alerts: { id: number; read: boolean }[]
}

// This:
export const structuredSelector = createStructuredSelector(
{
todos: (state: RootState) => state.todos,
alerts: (state: RootState) => state.alerts,
todoById: (state: RootState, id: number) => state.todos[id],
},
createSelector,
)

// Is essentially the same as this:
export const selector = createSelector(
[
(state: RootState) => state.todos,
(state: RootState) => state.alerts,
(state: RootState, id: number) => state.todos[id],
],
(todos, alerts, todoById) => {
return {
todos,
alerts,
todoById,
}
},
)

In your component:

createStructuredSelector/MyComponent.tsx
import type { RootState } from 'createStructuredSelector/modernUseCase'
import { structuredSelector } from 'createStructuredSelector/modernUseCase'
import type { FC } from 'react'
import { useSelector } from 'react-redux'

interface Props {
id: number
}

const MyComponent: FC<Props> = ({ id }) => {
const { todos, alerts, todoById } = useSelector((state: RootState) =>
structuredSelector(state, id),
)

return (
<div>
Next to do is:
<h2>{todoById.title}</h2>
<p>Description: {todoById.description}</p>
<ul>
<h3>All other to dos:</h3>
{todos.map(todo => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
</div>
)
}

Simple Use Case

const selectA = state => state.a
const selectB = state => state.b

// The result function in the following selector
// is simply building an object from the input selectors
const structuredSelector = createSelector(selectA, selectB, (a, b) => ({
a,
b,
}))

const result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }

createStructuredSelector takes an object whose properties are input selectors and returns a structured selector. The structured selector returns an object with the same keys as the inputSelectorsObject argument, but with the selectors replaced with their values.

const selectA = state => state.a
const selectB = state => state.b

const structuredSelector = createStructuredSelector({
x: selectA,
y: selectB,
})

const result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }

Structured selectors can be nested:

const nestedSelector = createStructuredSelector({
subA: createStructuredSelector({
selectorA,
selectorB,
}),
subB: createStructuredSelector({
selectorC,
selectorD,
}),
})

Defining a Pre-Typed createStructuredSelector

As of Reselect 5.1.0, you can create a "pre-typed" version of createStructuredSelector where the state type is predefined. This allows you to set the state type once, eliminating the need to specify it with every createStructuredSelector call.

To do this, you can call createStructuredSelector.withTypes<StateType>():

createStructuredSelector/withTypes.ts
import { createStructuredSelector } from 'reselect'

export interface RootState {
todos: { id: number; completed: boolean }[]
alerts: { id: number; read: boolean }[]
}

export const createStructuredAppSelector =
createStructuredSelector.withTypes<RootState>()

const structuredAppSelector = createStructuredAppSelector({
// Type of `state` is set to `RootState`, no need to manually set the type
todos: state => state.todos,
alerts: state => state.alerts,
todoById: (state, id: number) => state.todos[id],
})