re-reselect

所属分类:Python编程
开发工具:TypeScript
文件大小:0KB
下载次数:0
上传日期:2023-05-25 08:23:28
上 传 者sh-1993
说明:  通过更深入的记忆和缓存管理增强重新选择选择器。
(Enhance Reselect selectors with deeper memoization and cache management.)

文件列表:
.all-contributorsrc (6724, 2023-12-14)
.babelrc.js (197, 2023-12-14)
.editorconfig (179, 2023-12-14)
.npmrc (37, 2023-12-14)
.nvmrc (3, 2023-12-14)
.prettierignore (68, 2023-12-14)
.prettierrc (105, 2023-12-14)
CHANGELOG.md (4090, 2023-12-14)
CONTRIBUTING.md (426, 2023-12-14)
LICENSE.md (1053, 2023-12-14)
examples/ (0, 2023-12-14)
examples/1-join-selectors.md (2056, 2023-12-14)
examples/2-avoid-selector-factories.md (1786, 2023-12-14)
examples/3-cache-api-calls.md (1497, 2023-12-14)
examples/4-programmatic-keyselector-composition.md (1753, 2023-12-14)
examples/5-selectorator.md (1221, 2023-12-14)
examples/reselect-and-re-reselect.png (40181, 2023-12-14)
examples/reselect-and-re-reselect.svg (414623, 2023-12-14)
jest.setup.ts (223, 2023-12-14)
jest/ (0, 2023-12-14)
jest/__snapshots__/ (0, 2023-12-14)
jest/__snapshots__/bundles-snapshot.test.ts.snap (9963, 2023-12-14)
jest/bundles-snapshot.test.ts (272, 2023-12-14)
jest/cjs.config.js (202, 2023-12-14)
jest/es.config.js (201, 2023-12-14)
jest/umd.config.js (202, 2023-12-14)
package-lock.json (472071, 2023-12-14)
package.json (2769, 2023-12-14)
renovate.json (773, 2023-12-14)
rollup.config.js (844, 2023-12-14)
src/ (0, 2023-12-14)
src/__tests__/ (0, 2023-12-14)
src/__tests__/createCachedSelector.test.ts (10976, 2023-12-14)
... ...

# Re-reselect [![Build status][ci-badge]][ci] [![Npm version][npm-version-badge]][npm] [![Npm downloads][npm-downloads-badge]][npm] [![Test coverage report][coveralls-badge]][coveralls] From [v5](https://github.com/reduxjs/reselect/releases/tag/v5.0.1), `reselect` provides the ability to natively implement custom memoization/caching solutions via `createSelector` options. Most of the features `re-reselect` used to enable should be now natively available in `reselect`. `re-reselect` will try to support `reselect` v5+ for backward compatibility reasons. `re-reselect` is a lightweight wrapper around **[Reselect][reselect]** meant to enhance selectors with **deeper memoization** and **cache management**. **Switching between different arguments** using standard `reselect` selectors causes **cache invalidation** since default `reselect` cache has a **limit of one**. `re-reselect` **forwards different calls to different** `reselect` **selectors** stored in cache, so that computed/memoized values are retained. `re-reselect` **selectors work as normal** `reselect` **selectors** but they are able to determine when **creating a new selector or querying a cached one** on the fly, depending on the supplied arguments. ![Reselect and re-reselect][reselect-and-re-reselect-sketch] Useful to: - **Retain selector's cache** when sequentially **called with one/few different arguments** ([example][example-1]) - **Join similar selectors** into one - **Share selectors** with props across multiple component instances (see [reselect example][reselect-sharing-selectors] and [re-reselect solution][example-2]) - **Instantiate** selectors **on runtime** - Enhance `reselect` with [custom caching strategies][cache-objects-docs] ```js import {createCachedSelector} from 're-reselect'; // Normal reselect routine: declare "inputSelectors" and "resultFunc" const getUsers = state => state.users; const getLibraryId = (state, libraryName) => state.libraries[libraryName].id; const getUsersByLibrary = createCachedSelector( // inputSelectors getUsers, getLibraryId, // resultFunc (users, libraryId) => expensiveComputation(users, libraryId), )( // re-reselect keySelector (receives selectors' arguments) // Use "libraryName" as cacheKey (_state_, libraryName) => libraryName ); // Cached selectors behave like normal selectors: // 2 reselect selectors are created, called and cached const reactUsers = getUsersByLibrary(state, 'react'); const vueUsers = getUsersByLibrary(state, 'vue'); // This 3rd call hits the cache const reactUsersAgain = getUsersByLibrary(state, 'react'); // reactUsers === reactUsersAgain // "expensiveComputation" called twice in total ``` ## Table of contents - [Installation](#installation) - [Why? + example](#why--example) - [re-reselect solution](#re-reselect-solution) - [Other viable solutions](#other-viable-solutions) - [Examples](#examples) - [FAQ](#faq) - [API](#api) - [`createCachedSelector`](#createCachedSelector) - [`createStructuredCachedSelector`](#createStructuredCachedSelector) - [keySelector](#keyselector) - [options](#options) - [selector instance][selector-instance-docs] - [About re-reselect](#about-re-reselect) - [Todo's](#todos) - [Contributors](#contributors) ## Installation ```console npm install reselect npm install re-reselect ``` ## Why? + example Let's say `getData` is a `reselect` selector. ```js getData(state, itemId, 'dataA'); getData(state, itemId, 'dataB'); getData(state, itemId, 'dataA'); ``` The **3rd argument invalidates `reselect` cache** on each call, forcing `getData` to re-evaluate and return a new value. ### re-reselect solution `re-reselect` selectors keep a **cache of `reselect` selectors** stored by `cacheKey`. `cacheKey` is the return value of the `keySelector` function. It's by default a `string` or `number` but it can be anything depending on the chosen cache strategy (see [cache objects docs][cache-objects-docs]). `keySelector` is a custom function which: - takes the same arguments as the selector itself (in the example: `state`, `itemId`, `dataType`) - returns a `cacheKey` A **unique persisting `reselect` selector instance** stored in cache is used to compute data for a given `cacheKey` (1:1). Back to the example, we might setup `re-reselect` to retrieve data by **querying one of the cached selectors** using the 3rd argument as `cacheKey`, allowing cache invalidation only when `state` or `itemId` change (but not `dataType`): ```js const getData = createCachedSelector( state => state, (state, itemId) => itemId, (state, itemId, dataType) => dataType, (state, itemId, dataType) => expensiveComputation(state, itemId, dataType) )( (state, itemId, dataType) => dataType // Use dataType as cacheKey ); ``` **Replacing a selector with a cached selector is invisible to the consuming application since the API is the same.** **When a cached selector is called**, the following happens behind the scenes: 1. **Evaluate the `cacheKey`** for the current call by executing `keySelector` 2. **Retrieve** from cache the **`reselect` selector** stored under the given `cacheKey` 3. **Return found selector or create a new one** if no selector was found 4. **Call returned selector** with provided arguments ### Other viable solutions #### 1- Declare a different selector for each different call Easy, but doesn't scale. See ["join similar selectors" example][example-1]. #### 2- Declare a `makeGetPieceOfData` selector factory as explained in Reselect docs The solution suggested in [Reselect docs][reselect-sharing-selectors] is fine, but it has a few downsides: - Bloats your code by exposing both `get` selectors and `makeGet` selector factories - Needs to import/call the selector factory instead of directly using the selector - Two different instances, given the same arguments, will individually store and recompute the same result (read [this](https://github.com/reactjs/reselect/pull/213)) #### 3- Wrap your `makeGetPieceOfData` selector factory into a memoizer function and call the returning memoized selector This is what `re-reselect` actually does. ## Examples - [Join similar selectors][example-1] - [Avoid selector factories][example-2] - [Cache API calls][example-3] - [Programmatic keySelector composition][example-4] - [Usage with Selectorator][example-5] ## FAQ
How do I wrap my existing selector with re-reselect?
Given your `reselect` selectors: ```js import {createSelector} from 'reselect'; export const getMyData = createSelector( selectorA, selectorB, selectorC, (A, B, C) => doSomethingWith(A, B, C) ); ``` ...add `keySelector` in the second function call: ```js import {createCachedSelector} from 're-reselect'; export const getMyData = createCachedSelector( selectorA, selectorB, selectorC, (A, B, C) => doSomethingWith(A, B, C) )( (state, arg1, arg2) => arg2 // Use arg2 as cacheKey ); ``` Voilà, `getMyData` is ready for use! ```js const myData = getMyData(state, 'foo', 'bar'); ```
How do I use multiple inputs to set the cacheKey?
A few good examples and [a bonus](https://github.com/toomuchdesign/re-reselect/issues/3): ```js // Basic usage: use a single argument as cacheKey createCachedSelector( // ... )( (state, arg1, arg2, arg3) => arg3 ) // Use multiple arguments and chain them into a string createCachedSelector( // ... )( (state, arg1, arg2, arg3) => `${arg1}:${arg3}` ) // Extract properties from an object createCachedSelector( // ... )( (state, props) => `${props.a}:${props.b}` ) ```
How do I limit the cache size?
Use a [`cacheObject`][cache-objects-docs] which provides that feature by supplying a [`cacheObject` option](#cacheobject). You can also write **your own cache strategy**!
How to share a selector across multiple components while passing in props and retaining memoization?
[This example][example-2] shows how `re-reselect` would solve the scenario described in [reselect docs][reselect-sharing-selectors].
How do I test a re-reselect selector?
Like a normal reselect selector! `re-reselect` selectors expose the same `reselect` testing methods: - `dependencies` - `resultFunc` - `recomputations` - `resetRecomputations` Read more about testing selectors on [`reselect` docs][reselect-test-selectors]. #### Testing `reselect` selectors stored in the cache Each **re-reselect** selector exposes a `getMatchingSelector` method which returns the **underlying matching selector** instance for the given arguments, **instead of the result**. `getMatchingSelector` expects the same arguments as a normal selector call **BUT returns the instance of the cached selector itself**. Once you get a selector instance you can call [its public methods][reselect-selectors-methods]. ```js import {createCachedSelector} from 're-reselect'; export const getMyData = createCachedSelector(selectorA, selectorB, (A, B) => doSomethingWith(A, B) )( (state, arg1) => arg1 // cacheKey ); // Call your selector const myFooData = getMyData(state, 'foo'); const myBarData = getMyData(state, 'bar'); // Call getMatchingSelector method to retrieve underlying reselect selectors // which generated "myFooData" and "myBarData" results const myFooDataSelector = getMyData.getMatchingSelector(state, 'foo'); const myBarDataSelector = getMyData.getMatchingSelector(state, 'bar'); // Call reselect's selectors methods myFooDataSelector.recomputations(); myFooDataSelector.resetRecomputations(); ```
## API ### createCachedSelector ```js import {createCachedSelector} from 're-reselect'; createCachedSelector( // ...reselect's `createSelector` arguments )( keySelector | { options } ) ``` Takes the same arguments as reselect's [`createSelector`][reselect-create-selector] and returns a new function which accepts a [`keySelector`](#keyselector) or an [`options`](#options) object. **Returns** a [selector instance][selector-instance-docs]. ### createStructuredCachedSelector ```js import {createStructuredCachedSelector} from 're-reselect'; createStructuredCachedSelector( // ...reselect's `createStructuredSelector` arguments )( keySelector | { options } ) ``` Takes the same arguments as reselect's [`createStructuredSelector`][reselect-create-structured-selector] and returns a new function which accepts a [`keySelector`](#keyselector) or an [`options`](#options) object. **Returns** a [selector instance][selector-instance-docs]. ### keySelector A custom function receiving the same arguments as your selectors (and `inputSelectors`) and **returning a `cacheKey`**. `cacheKey` is **by default a `string` or `number`** but can be anything depending on the chosen cache strategy (see [`cacheObject` option](#optionscacheobject)). The `keySelector` idea comes from [Lodash's .memoize resolver][lodash-memoize]. ### options #### keySelector Type: `function`
Default: `undefined` The [`keySelector`](#keyselector) used by the cached selector. #### cacheObject Type: `object`
Default: [`FlatObjectCache`][cache-objects-docs] An optional custom **cache strategy object** to handle the caching behaviour. Read more about [re-reselect's custom cache here][cache-objects-docs]. #### keySelectorCreator Type: `function`
Default: `undefined` An optional function with the following signature returning the [`keySelector`](#keyselector) used by the cached selector. ```typescript type keySelectorCreator = (selectorInputs: { inputSelectors: InputSelector[]; resultFunc: ResultFunc; keySelector: KeySelector; }) => KeySelector; ``` This allows the ability to dynamically **generate `keySelectors` on runtime** based on provided `inputSelectors`/`resultFunc` supporting [**key selectors composition**](https://github.com/toomuchdesign/re-reselect/pull/73). It overrides any provided `keySelector`. See [programmatic keySelector composition][example-4] example. #### selectorCreator Type: `function`
Default: `reselect`'s [`createSelector`][reselect-create-selector] An optional function describing a [custom version of createSelector][reselect-create-selector-creator]. ### re-reselect selector instance `createCachedSelector` and `createStructuredCachedSelector` return a **selector instance** which extends the API of a **standard reselect selector**. > The followings are advanced methods and you won't need them for basic usage! #### selector`.getMatchingSelector(selectorArguments)` Retrieve the selector responding to the given arguments. #### selector`.removeMatchingSelector(selectorArguments)` Remove from the cache the selector responding to the given arguments. #### selector`.cache` Get the cacheObject instance being used by the selector (for advanced caching operations like [this](https://github.com/toomuchdesign/re-reselect/issues/40)). #### selector`.clearCache()` Clear whole `selector` cache. #### selector`.dependencies` Get an array containing the provided `inputSelectors`. Refer to relevant discussion on [Reselect repo][reselect-test-selectors-dependencies]. #### selector`.resultFunc` Get `resultFunc` for easily [testing composed selectors][reselect-test-selectors]. #### selector`.recomputations()` Return the number of times the selector's result function has been recomputed. #### selector`.resetRecomputations()` Reset `recomputations` count. #### selector`.keySelector` Get `keySelector` for utility compositions or testing. ## About re-reselect - [re-reselect your whole redux state](https://patrickdesjardins.com/blog/re-reselect-your-whole-redux-state) - [Understanding reselect and re-reselect](http://alexnitta.com/understanding-reselect-and-re-reselect/) - [React re-reselect: Better memoization and cache management](https://blog.logrocket.com/react-re-reselect-better-memoization-cache-management/) - [Advanced Redux patterns: selectors](https://blog.brainsandbeards.com/advanced-redux-patterns-selectors-cb9f88381d74) - [Be selective with your state](https://medium.com/riipen-engineering/be-selective-with-your-state-8f1be76cb9f4) - [A swift developer’s React Native experience](https://swiftwithjustin.co/2018/06/24/a-swift-developers-react-native-experience) - [5 key Redux libraries to improve code reuse](https://blog.logrocket.com/5-redux-libraries-to-improve-code-reuse-9f93eaceaa83) - [Rematch's docs](https://github.com/rematch/rematch/blob/1.1.0/plugins/select/README.md#re-reselect) - [Redux re-reselect playground](https://codesandbox.io/s/135rwqj2jj) ## Todo's - Improve tests readability - Port to native TS based on reselect v5 approach - Find out whether `re-reselect` should be deprecated in favour of `reselect` memoization/cache options ## Contributors Thanks to you all ([emoji key][docs-all-contributors]):
Andrea Carraro
Andrea Carraro

Stepan Burguchev
Stepan Burguchev

Sergei Grishchenko
Sergei Grishchenko

Mateusz Burzyński
Mateusz Burzyński

Mitch Robb
Mitch Robb

Stephane Rufer
Stephane Rufer

Tracy Mullen
Tracy Mullen


相关文件


收藏者