Alok
Alok

Reputation: 10544

Difference between createSelector and createDraftSafeSelector API in Redux Toolkit

createSelector mentioned at https://github.com/reduxjs/reselect

createSelector API, which generates memoized selector functions. createSelector accepts one or more "input" selectors, which extract values from arguments, and an "output" selector that receives the extracted values and should return a derived value. If the generated selector is called multiple times, the output will only be recalculated when the extracted values have changed.

createDraftSafeSelector mentioned at https://redux-toolkit.js.org/api/createSelector

createDraftSafeSelector allows to create selectors that can safely be used inside of createReducer and createSlice reducers with Immer-powered mutable logic. When used with plain state values, the selector will still memoize normally based on the inputs. But, when used with Immer draft values, the selector will err on the side of recalculating the results, just to be safe.

I am new to react and redux design patterns so could not understand the difference and purpose of createDraftSafeSelector.

What is the difference in both API? What can be an example to understand the difference?

Upvotes: 3

Views: 4515

Answers (2)

Lin Du
Lin Du

Reputation: 102237

See the real-world usage of the draft safe selector, interactionsBucketsSelectors.selectById(state.interactionsBuckets, convPk)

We can pass the draft state of immer.js in the draft safe selector in RTK case reducer.

The selectById draft safe selector created in getSelectors().

createDraftSafeSelector is a wrapper for createSelector, it not only supports the general JS object state that createSelector can handle, but also supports the draft State of immerjs, see source code:

import { current, isDraft } from 'immer'
import { createSelector } from 'reselect'

/**
 * "Draft-Safe" version of `reselect`'s `createSelector`:
 * If an `immer`-drafted object is passed into the resulting selector's first argument,
 * the selector will act on the current draft value, instead of returning a cached value
 * that might be possibly outdated if the draft has been modified since.
 * @public
 */
export const createDraftSafeSelector: typeof createSelector = (
  ...args: unknown[]
) => {
  const selector = (createSelector as any)(...args)
  const wrappedSelector = (value: unknown, ...rest: unknown[]) =>
    selector(isDraft(value) ? current(value) : value, ...rest)
  return wrappedSelector as any
}

You may also want to see these two test cases about the difference between createSelector and createDraftSafeSelector.

If you don't pass the draft state of immerjs to selectors, you don't need to use createDraftSafeSelector.

Upvotes: 0

phry
phry

Reputation: 44086

A selector created with createDraftSafeSelector can be used safely within createReducer or createSlice reducers, which is not possible with createSelector, as that one solely relies on object reference equality.

A selector created with createSelector would always return the same result for one reducer call even if you modified the state in-between.

Most people never use selectors in reducers, so you will probably never need it.

Upvotes: 5

Related Questions