{"id":13727425,"url":"https://github.com/toomuchdesign/re-reselect","last_synced_at":"2025-05-13T00:14:43.752Z","repository":{"id":39176717,"uuid":"82931976","full_name":"toomuchdesign/re-reselect","owner":"toomuchdesign","description":"Enhance Reselect selectors with deeper memoization and cache management.","archived":false,"fork":false,"pushed_at":"2025-05-08T09:05:32.000Z","size":2723,"stargazers_count":1090,"open_issues_count":5,"forks_count":46,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-05-09T13:02:00.659Z","etag":null,"topics":["memoization","reactjs","reselect"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/toomuchdesign.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-02-23T13:53:41.000Z","updated_at":"2025-05-07T09:14:23.000Z","dependencies_parsed_at":"2023-10-21T13:11:03.985Z","dependency_job_id":"42e7a330-66fe-4471-acff-bc339f3fe01f","html_url":"https://github.com/toomuchdesign/re-reselect","commit_stats":{"total_commits":412,"total_committers":23,"mean_commits":17.91304347826087,"dds":0.5436893203883495,"last_synced_commit":"c9e2b8050bef38fa12bb1c8dd130113cb2d332cb"},"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toomuchdesign%2Fre-reselect","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toomuchdesign%2Fre-reselect/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toomuchdesign%2Fre-reselect/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toomuchdesign%2Fre-reselect/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/toomuchdesign","download_url":"https://codeload.github.com/toomuchdesign/re-reselect/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253492649,"owners_count":21916969,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["memoization","reactjs","reselect"],"created_at":"2024-08-03T01:03:55.362Z","updated_at":"2025-05-13T00:14:43.711Z","avatar_url":"https://github.com/toomuchdesign.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# Re-reselect\n\n[![Build status][ci-badge]][ci]\n[![Npm version][npm-version-badge]][npm]\n[![Npm downloads][npm-downloads-badge]][npm]\n[![Test coverage report][coveralls-badge]][coveralls]\n\nFrom [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.\n\n`re-reselect` is a lightweight wrapper around **[Reselect][reselect]** meant to enhance selectors with **deeper memoization** and **cache management**.\n\n**Switching between different arguments** using standard `reselect` selectors causes **cache invalidation** since default `reselect` cache has a **limit of one**.\n\n`re-reselect` **forwards different calls to different** `reselect` **selectors** stored in cache, so that computed/memoized values are retained.\n\n`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.\n\n![Reselect and re-reselect][reselect-and-re-reselect-sketch]\n\nUseful to:\n\n- **Retain selector's cache** when sequentially **called with one/few different arguments** ([example][example-1])\n- **Join similar selectors** into one\n- **Share selectors** with props across multiple component instances (see [reselect example][reselect-sharing-selectors] and [re-reselect solution][example-2])\n- **Instantiate** selectors **on runtime**\n- Enhance `reselect` with [custom caching strategies][cache-objects-docs]\n\n\u003c!-- prettier-ignore --\u003e\n```js\nimport {createCachedSelector} from 're-reselect';\n\n// Normal reselect routine: declare \"inputSelectors\" and \"resultFunc\"\nconst getUsers = state =\u003e state.users;\nconst getLibraryId = (state, libraryName) =\u003e state.libraries[libraryName].id;\n\nconst getUsersByLibrary = createCachedSelector(\n  // inputSelectors\n  getUsers,\n  getLibraryId,\n\n  // resultFunc\n  (users, libraryId) =\u003e expensiveComputation(users, libraryId),\n)(\n  // re-reselect keySelector (receives selectors' arguments)\n  // Use \"libraryName\" as cacheKey\n  (_state_, libraryName) =\u003e libraryName\n);\n\n// Cached selectors behave like normal selectors:\n// 2 reselect selectors are created, called and cached\nconst reactUsers = getUsersByLibrary(state, 'react');\nconst vueUsers = getUsersByLibrary(state, 'vue');\n\n// This 3rd call hits the cache\nconst reactUsersAgain = getUsersByLibrary(state, 'react');\n// reactUsers === reactUsersAgain\n// \"expensiveComputation\" called twice in total\n```\n\n## Table of contents\n\n- [Installation](#installation)\n- [Why? + example](#why--example)\n  - [re-reselect solution](#re-reselect-solution)\n  - [Other viable solutions](#other-viable-solutions)\n- [Examples](#examples)\n- [FAQ](#faq)\n- [API](#api)\n  - [`createCachedSelector`](#createCachedSelector)\n  - [`createStructuredCachedSelector`](#createStructuredCachedSelector)\n  - [keySelector](#keyselector)\n  - [options](#options)\n  - [selector instance][selector-instance-docs]\n- [About re-reselect](#about-re-reselect)\n- [Todo's](#todos)\n- [Contributors](#contributors)\n\n## Installation\n\n```console\nnpm install reselect\nnpm install re-reselect\n```\n\n## Why? + example\n\nLet's say `getData` is a `reselect` selector.\n\n```js\ngetData(state, itemId, 'dataA');\ngetData(state, itemId, 'dataB');\ngetData(state, itemId, 'dataA');\n```\n\nThe **3rd argument invalidates `reselect` cache** on each call, forcing `getData` to re-evaluate and return a new value.\n\n### re-reselect solution\n\n`re-reselect` selectors keep a **cache of `reselect` selectors** stored by `cacheKey`.\n\n\u003c!-- Please note that part of this lines are repeated in #api chapter --\u003e\n\n`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]).\n\n`keySelector` is a custom function which:\n\n- takes the same arguments as the selector itself (in the example: `state`, `itemId`, `dataType`)\n- returns a `cacheKey`\n\nA **unique persisting `reselect` selector instance** stored in cache is used to compute data for a given `cacheKey` (1:1).\n\nBack 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`):\n\n\u003c!-- prettier-ignore --\u003e\n```js\nconst getData = createCachedSelector(\n  state =\u003e state,\n  (state, itemId) =\u003e itemId,\n  (state, itemId, dataType) =\u003e dataType,\n  (state, itemId, dataType) =\u003e expensiveComputation(state, itemId, dataType)\n)(\n  (state, itemId, dataType) =\u003e dataType // Use dataType as cacheKey\n);\n```\n\n**Replacing a selector with a cached selector is invisible to the consuming application since the API is the same.**\n\n**When a cached selector is called**, the following happens behind the scenes:\n\n1.  **Evaluate the `cacheKey`** for the current call by executing `keySelector`\n2.  **Retrieve** from cache the **`reselect` selector** stored under the given `cacheKey`\n3.  **Return found selector or create a new one** if no selector was found\n4.  **Call returned selector** with provided arguments\n\n### Other viable solutions\n\n#### 1- Declare a different selector for each different call\n\nEasy, but doesn't scale. See [\"join similar selectors\" example][example-1].\n\n#### 2- Declare a `makeGetPieceOfData` selector factory as explained in Reselect docs\n\nThe solution suggested in [Reselect docs][reselect-sharing-selectors] is fine, but it has a few downsides:\n\n- Bloats your code by exposing both `get` selectors and `makeGet` selector factories\n- Needs to import/call the selector factory instead of directly using the selector\n- Two different instances, given the same arguments, will individually store and recompute the same result (read [this](https://github.com/reactjs/reselect/pull/213))\n\n#### 3- Wrap your `makeGetPieceOfData` selector factory into a memoizer function and call the returning memoized selector\n\nThis is what `re-reselect` actually does. 😀\n\n## Examples\n\n- [Join similar selectors][example-1]\n- [Avoid selector factories][example-2]\n- [Cache API calls][example-3]\n- [Programmatic keySelector composition][example-4]\n- [Usage with Selectorator][example-5]\n\n## FAQ\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003eHow do I wrap my existing selector with re-reselect?\u003c/b\u003e\n  \u003c/summary\u003e\n  \u003cbr/\u003e\n\nGiven your `reselect` selectors:\n\n  \u003c!-- prettier-ignore --\u003e\n\n```js\nimport {createSelector} from 'reselect';\n\nexport const getMyData = createSelector(\n  selectorA,\n  selectorB,\n  selectorC,\n  (A, B, C) =\u003e doSomethingWith(A, B, C)\n);\n```\n\n...add `keySelector` in the second function call:\n\n  \u003c!-- prettier-ignore --\u003e\n\n```js\nimport {createCachedSelector} from 're-reselect';\n\nexport const getMyData = createCachedSelector(\n  selectorA,\n  selectorB,\n  selectorC,\n  (A, B, C) =\u003e doSomethingWith(A, B, C)\n)(\n  (state, arg1, arg2) =\u003e arg2 // Use arg2 as cacheKey\n);\n```\n\nVoilà, `getMyData` is ready for use!\n\n```js\nconst myData = getMyData(state, 'foo', 'bar');\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003eHow do I use multiple inputs to set the cacheKey?\u003c/b\u003e\n  \u003c/summary\u003e\n  \u003cbr/\u003e\n\nA few good examples and [a bonus](https://github.com/toomuchdesign/re-reselect/issues/3):\n\n\u003c!-- prettier-ignore --\u003e\n```js\n// Basic usage: use a single argument as cacheKey\ncreateCachedSelector(\n  // ...\n)(\n  (state, arg1, arg2, arg3) =\u003e arg3\n)\n\n// Use multiple arguments and chain them into a string\ncreateCachedSelector(\n  // ...\n)(\n  (state, arg1, arg2, arg3) =\u003e `${arg1}:${arg3}`\n)\n\n// Extract properties from an object\ncreateCachedSelector(\n  // ...\n)(\n  (state, props) =\u003e `${props.a}:${props.b}`\n)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003eHow do I limit the cache size?\u003c/b\u003e\n  \u003c/summary\u003e\n  \u003cbr/\u003e\n\nUse a [`cacheObject`][cache-objects-docs] which provides that feature by supplying a [`cacheObject` option](#cacheobject).\n\nYou can also write **your own cache strategy**!\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003eHow to share a selector across multiple components while passing in props and retaining memoization?\u003c/b\u003e\n  \u003c/summary\u003e\n  \u003cbr/\u003e\n\n[This example][example-2] shows how `re-reselect` would solve the scenario described in [reselect docs][reselect-sharing-selectors].\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003eHow do I test a re-reselect selector?\u003c/b\u003e\n  \u003c/summary\u003e\n  \u003cbr/\u003e\n\nLike a normal reselect selector!\n\n`re-reselect` selectors expose the same `reselect` testing methods:\n\n- `dependencies`\n- `resultFunc`\n- `recomputations`\n- `resetRecomputations`\n\nRead more about testing selectors on [`reselect` docs][reselect-test-selectors].\n\n#### Testing `reselect` selectors stored in the cache\n\nEach **re-reselect** selector exposes a `getMatchingSelector` method which returns the **underlying matching selector** instance for the given arguments, **instead of the result**.\n\n`getMatchingSelector` expects the same arguments as a normal selector call **BUT returns the instance of the cached selector itself**.\n\nOnce you get a selector instance you can call [its public methods][reselect-selectors-methods].\n\n\u003c!-- prettier-ignore --\u003e\n```js\nimport {createCachedSelector} from 're-reselect';\n\nexport const getMyData = createCachedSelector(selectorA, selectorB, (A, B) =\u003e\n  doSomethingWith(A, B)\n)(\n  (state, arg1) =\u003e arg1 // cacheKey\n);\n\n// Call your selector\nconst myFooData = getMyData(state, 'foo');\nconst myBarData = getMyData(state, 'bar');\n\n// Call getMatchingSelector method to retrieve underlying reselect selectors\n// which generated \"myFooData\" and \"myBarData\" results\nconst myFooDataSelector = getMyData.getMatchingSelector(state, 'foo');\nconst myBarDataSelector = getMyData.getMatchingSelector(state, 'bar');\n\n// Call reselect's selectors methods\nmyFooDataSelector.recomputations();\nmyFooDataSelector.resetRecomputations();\n```\n\n\u003c/details\u003e\n\n## API\n\n### createCachedSelector\n\n\u003c!-- prettier-ignore --\u003e\n```js\nimport {createCachedSelector} from 're-reselect';\n\ncreateCachedSelector(\n  // ...reselect's `createSelector` arguments\n)(\n  keySelector | { options }\n)\n```\n\nTakes 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.\n\n**Returns** a [selector instance][selector-instance-docs].\n\n### createStructuredCachedSelector\n\n\u003c!-- prettier-ignore --\u003e\n```js\nimport {createStructuredCachedSelector} from 're-reselect';\n\ncreateStructuredCachedSelector(\n  // ...reselect's `createStructuredSelector` arguments\n)(\n  keySelector | { options }\n)\n```\n\nTakes 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.\n\n**Returns** a [selector instance][selector-instance-docs].\n\n### keySelector\n\nA custom function receiving the same arguments as your selectors (and `inputSelectors`) and **returning a `cacheKey`**.\n\n`cacheKey` is **by default a `string` or `number`** but can be anything depending on the chosen cache strategy (see [`cacheObject` option](#optionscacheobject)).\n\nThe `keySelector` idea comes from [Lodash's .memoize resolver][lodash-memoize].\n\n### options\n\n#### keySelector\n\nType: `function`\u003cbr /\u003e\nDefault: `undefined`\n\nThe [`keySelector`](#keyselector) used by the cached selector.\n\n#### cacheObject\n\nType: `object`\u003cbr /\u003e\nDefault: [`FlatObjectCache`][cache-objects-docs]\n\nAn optional custom **cache strategy object** to handle the caching behaviour. Read more about [re-reselect's custom cache here][cache-objects-docs].\n\n#### keySelectorCreator\n\nType: `function`\u003cbr /\u003e\nDefault: `undefined`\n\nAn optional function with the following signature returning the [`keySelector`](#keyselector) used by the cached selector.\n\n```typescript\ntype keySelectorCreator = (selectorInputs: {\n  inputSelectors: InputSelector[];\n  resultFunc: ResultFunc;\n  keySelector: KeySelector;\n}) =\u003e KeySelector;\n```\n\nThis 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`.\n\nSee [programmatic keySelector composition][example-4] example.\n\n#### selectorCreator\n\nType: `function`\u003cbr /\u003e\nDefault: `reselect`'s [`createSelector`][reselect-create-selector]\n\nAn optional function describing a [custom version of createSelector][reselect-create-selector-creator].\n\n### re-reselect selector instance\n\n`createCachedSelector` and `createStructuredCachedSelector` return a **selector instance** which extends the API of a **standard reselect selector**.\n\n\u003e The followings are advanced methods and you won't need them for basic usage!\n\n#### selector`.getMatchingSelector(selectorArguments)`\n\nRetrieve the selector responding to the given arguments.\n\n#### selector`.removeMatchingSelector(selectorArguments)`\n\nRemove from the cache the selector responding to the given arguments.\n\n#### selector`.cache`\n\nGet the cacheObject instance being used by the selector (for advanced caching operations like [this](https://github.com/toomuchdesign/re-reselect/issues/40)).\n\n#### selector`.clearCache()`\n\nClear whole `selector` cache.\n\n#### selector`.dependencies`\n\nGet an array containing the provided `inputSelectors`. Refer to relevant discussion on [Reselect repo][reselect-test-selectors-dependencies].\n\n#### selector`.resultFunc`\n\nGet `resultFunc` for easily [testing composed selectors][reselect-test-selectors].\n\n#### selector`.recomputations()`\n\nReturn the number of times the selector's result function has been recomputed.\n\n#### selector`.resetRecomputations()`\n\nReset `recomputations` count.\n\n#### selector`.keySelector`\n\nGet `keySelector` for utility compositions or testing.\n\n## About re-reselect\n\n- [re-reselect your whole redux state](https://patrickdesjardins.com/blog/re-reselect-your-whole-redux-state)\n- [Understanding reselect and re-reselect](http://alexnitta.com/understanding-reselect-and-re-reselect/)\n- [React re-reselect: Better memoization and cache management](https://blog.logrocket.com/react-re-reselect-better-memoization-cache-management/)\n- [Advanced Redux patterns: selectors](https://blog.brainsandbeards.com/advanced-redux-patterns-selectors-cb9f88381d74)\n- [Be selective with your state](https://medium.com/riipen-engineering/be-selective-with-your-state-8f1be76cb9f4)\n- [A swift developer’s React Native experience](https://swiftwithjustin.co/2018/06/24/a-swift-developers-react-native-experience)\n- [5 key Redux libraries to improve code reuse](https://blog.logrocket.com/5-redux-libraries-to-improve-code-reuse-9f93eaceaa83)\n- [Rematch's docs](https://github.com/rematch/rematch/blob/1.1.0/plugins/select/README.md#re-reselect)\n- [Redux re-reselect playground](https://codesandbox.io/s/135rwqj2jj)\n\n## Todo's\n\n- Improve tests readability\n- Port to native TS based on reselect v5 approach\n- Find out whether `re-reselect` should be deprecated in favour of `reselect` memoization/cache options\n\n## Contributors\n\nThanks to you all ([emoji key][docs-all-contributors]):\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"http://www.andreacarraro.it\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/4573549?v=4?s=100\" width=\"100px;\" alt=\"Andrea Carraro\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAndrea Carraro\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=toomuchdesign\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=toomuchdesign\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"#infra-toomuchdesign\" title=\"Infrastructure (Hosting, Build-Tools, etc)\"\u003e🚇\u003c/a\u003e \u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=toomuchdesign\" title=\"Tests\"\u003e⚠️\u003c/a\u003e \u003ca href=\"https://github.com/toomuchdesign/re-reselect/pulls?q=is%3Apr+reviewed-by%3Atoomuchdesign\" title=\"Reviewed Pull Requests\"\u003e👀\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/xsburg\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/830824?v=4?s=100\" width=\"100px;\" alt=\"Stepan Burguchev\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eStepan Burguchev\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=xsburg\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"#ideas-xsburg\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"#question-xsburg\" title=\"Answering Questions\"\u003e💬\u003c/a\u003e \u003ca href=\"https://github.com/toomuchdesign/re-reselect/pulls?q=is%3Apr+reviewed-by%3Axsburg\" title=\"Reviewed Pull Requests\"\u003e👀\u003c/a\u003e \u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=xsburg\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/sgrishchenko\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/15995890?v=4?s=100\" width=\"100px;\" alt=\"Sergei Grishchenko\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eSergei Grishchenko\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=sgrishchenko\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"#ideas-sgrishchenko\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=sgrishchenko\" title=\"Tests\"\u003e⚠️\u003c/a\u003e \u003ca href=\"#tool-sgrishchenko\" title=\"Tools\"\u003e🔧\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/Andarist\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/9800850?v=4?s=100\" width=\"100px;\" alt=\"Mateusz Burzyński\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eMateusz Burzyński\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=Andarist\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"#infra-Andarist\" title=\"Infrastructure (Hosting, Build-Tools, etc)\"\u003e🚇\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://olslash.github.io/\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/693493?v=4?s=100\" width=\"100px;\" alt=\"Mitch Robb\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eMitch Robb\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=olslash\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=olslash\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/rufman\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/1128559?v=4?s=100\" width=\"100px;\" alt=\"Stephane Rufer\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eStephane Rufer\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=rufman\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=rufman\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/spiffysparrow\"\u003e\u003cimg src=\"https://avatars0.githubusercontent.com/u/2788860?v=4?s=100\" width=\"100px;\" alt=\"Tracy Mullen\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eTracy Mullen\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=spiffysparrow\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=spiffysparrow\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://www.skc.name\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/4211838?v=4?s=100\" width=\"100px;\" alt=\"Sushain Cherivirala\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eSushain Cherivirala\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=sushain97\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://twitter.com/MaoStevemao\"\u003e\u003cimg src=\"https://avatars0.githubusercontent.com/u/6316590?v=4?s=100\" width=\"100px;\" alt=\"Steve Mao\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eSteve Mao\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=stevemao\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/Dante-101\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/1428826?v=4?s=100\" width=\"100px;\" alt=\"Gaurav Lahoti\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eGaurav Lahoti\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/issues?q=author%3ADante-101\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"http://lon.im\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/13602053?v=4?s=100\" width=\"100px;\" alt=\"Lon\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eLon\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/issues?q=author%3Acnlon\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/bratushka\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/5492495?v=4?s=100\" width=\"100px;\" alt=\"bratushka\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003ebratushka\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=bratushka\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://andrz.me\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/615381?v=4?s=100\" width=\"100px;\" alt=\"Anders D. Johnson\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAnders D. Johnson\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=AndersDJohnson\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/wormyy\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/8556724?v=4?s=100\" width=\"100px;\" alt=\"Július Retzer\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eJúlius Retzer\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=wormyy\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/maartenschumacher\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/10407025?v=4?s=100\" width=\"100px;\" alt=\"Maarten Schumacher\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eMaarten Schumacher\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#ideas-maartenschumacher\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/alexanderjarvis\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/664238?v=4?s=100\" width=\"100px;\" alt=\"Alexander Jarvis\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAlexander Jarvis\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#ideas-alexanderjarvis\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/greggb\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/514026?v=4?s=100\" width=\"100px;\" alt=\"Gregg B\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eGregg B\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#example-greggb\" title=\"Examples\"\u003e💡\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"http://ianobermiller.com\"\u003e\u003cimg src=\"https://avatars0.githubusercontent.com/u/897931?v=4?s=100\" width=\"100px;\" alt=\"Ian Obermiller\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eIan Obermiller\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/pulls?q=is%3Apr+reviewed-by%3Aianobermiller\" title=\"Reviewed Pull Requests\"\u003e👀\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/lukyth\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/7040242?v=4?s=100\" width=\"100px;\" alt=\"Kanitkorn Sujautra\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eKanitkorn Sujautra\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=lukyth\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/suark\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/6233440?v=4?s=100\" width=\"100px;\" alt=\"Brian Kraus\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eBrian Kraus\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=suark\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/el-dav\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/7252227?v=4?s=100\" width=\"100px;\" alt=\"el-dav\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eel-dav\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/issues?q=author%3Ael-dav\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://augustin-riedinger.fr\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/1970156?v=4?s=100\" width=\"100px;\" alt=\"Augustin Riedinger\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAugustin Riedinger\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#ideas-augnustin\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/RichardForrester\"\u003e\u003cimg src=\"https://avatars0.githubusercontent.com/u/12902182?v=4?s=100\" width=\"100px;\" alt=\"RichardForrester\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eRichardForrester\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#ideas-RichardForrester\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://alfonsomillan.com/\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/25711137?v=4?s=100\" width=\"100px;\" alt=\"Alfonso Millan\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAlfonso Millan\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=mechmillan\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/parkerault\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/78856?v=4?s=100\" width=\"100px;\" alt=\"parkerault\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eparkerault\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/issues?q=author%3Aparkerault\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/dahannes\"\u003e\u003cimg src=\"https://avatars0.githubusercontent.com/u/2493211?v=4?s=100\" width=\"100px;\" alt=\"johannes\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003ejohannes\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/issues?q=author%3Adahannes\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/alexdlm\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/1270606?v=4?s=100\" width=\"100px;\" alt=\"Alex de la Mare\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAlex de la Mare\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/issues?q=author%3Aalexdlm\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=alexdlm\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://devblog.pro/\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/6467881?v=4?s=100\" width=\"100px;\" alt=\"Alex Khizhnyi\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAlex Khizhnyi\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/toomuchdesign/re-reselect/commits?author=veksa\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003c!-- markdownlint-restore --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\n[reselect]: https://github.com/reactjs/reselect\n[reselect-sharing-selectors]: https://github.com/reduxjs/reselect/tree/v4.0.0#sharing-selectors-with-props-across-multiple-component-instances\n[reselect-test-selectors]: https://github.com/reactjs/reselect/tree/v4.0.0#q-how-do-i-test-a-selector\n[reselect-test-selectors-dependencies]: https://github.com/reduxjs/reselect/issues/76#issuecomment-299194186\n[reselect-selectors-methods]: https://github.com/reduxjs/reselect/blob/v4.0.0/src/index.js#L81\n[reselect-create-selector]: https://github.com/reactjs/reselect/tree/v4.0.0#createselectorinputselectors--inputselectors-resultfunc\n[reselect-create-structured-selector]: https://github.com/reduxjs/reselect/tree/v4.0.0#createstructuredselectorinputselectors-selectorcreator--createselector\n[reselect-create-selector-creator]: https://github.com/reactjs/reselect/tree/v4.0.0#createselectorcreatormemoize-memoizeoptions\n[lodash-memoize]: https://lodash.com/docs/4.17.4#memoize\n[ci-badge]: https://github.com/toomuchdesign/re-reselect/actions/workflows/ci.yml/badge.svg\n[ci]: https://github.com/toomuchdesign/re-reselect/actions/workflows/ci.yml\n[coveralls-badge]: https://coveralls.io/repos/github/toomuchdesign/re-reselect/badge.svg?branch=master\n[coveralls]: https://coveralls.io/github/toomuchdesign/re-reselect?branch=master\n[npm]: https://www.npmjs.com/package/re-reselect\n[npm-version-badge]: https://img.shields.io/npm/v/re-reselect.svg\n[npm-downloads-badge]: https://img.shields.io/npm/dm/re-reselect.svg\n[reselect-and-re-reselect-sketch]: examples/reselect-and-re-reselect.png?raw=true\n[example-1]: examples/1-join-selectors.md\n[example-2]: examples/2-avoid-selector-factories.md\n[example-3]: examples/3-cache-api-calls.md\n[example-4]: examples/4-programmatic-keyselector-composition.md\n[example-5]: examples/5-selectorator.md\n[selector-instance-docs]: #re-reselect-selector-instance\n[cache-objects-docs]: src/cache#readme\n[docs-all-contributors]: https://allcontributors.org/docs/en/emoji-key\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftoomuchdesign%2Fre-reselect","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftoomuchdesign%2Fre-reselect","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftoomuchdesign%2Fre-reselect/lists"}