{"id":19451200,"url":"https://github.com/thekashey/memoize-state","last_synced_at":"2025-04-12T20:46:31.059Z","repository":{"id":29357886,"uuid":"121081215","full_name":"theKashey/memoize-state","owner":"theKashey","description":"The magic memoization for the State management. ✨🧠","archived":false,"fork":false,"pushed_at":"2022-12-09T18:52:18.000Z","size":1838,"stargazers_count":328,"open_issues_count":35,"forks_count":16,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-12T20:46:23.777Z","etag":null,"topics":["mapstatetoprops","memoization","memoization-library","memoize","performance","proxy","selector"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/theKashey.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-02-11T03:42:02.000Z","updated_at":"2025-01-03T08:12:26.000Z","dependencies_parsed_at":"2023-01-14T14:45:34.864Z","dependency_job_id":null,"html_url":"https://github.com/theKashey/memoize-state","commit_stats":null,"previous_names":[],"tags_count":43,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theKashey%2Fmemoize-state","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theKashey%2Fmemoize-state/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theKashey%2Fmemoize-state/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theKashey%2Fmemoize-state/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/theKashey","download_url":"https://codeload.github.com/theKashey/memoize-state/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248631716,"owners_count":21136559,"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":["mapstatetoprops","memoization","memoization-library","memoize","performance","proxy","selector"],"created_at":"2024-11-10T16:40:41.929Z","updated_at":"2025-04-12T20:46:31.036Z","avatar_url":"https://github.com/theKashey.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"memoize-state\n=====\n\n[![CircleCI status](https://img.shields.io/circleci/project/github/theKashey/memoize-state/master.svg?style=flat-square)](https://circleci.com/gh/theKashey/memoize-state/tree/master)\n[![coverage-badge](https://img.shields.io/codecov/c/github/thekashey/memoize-state.svg?style=flat-square)](https://codecov.io/github/thekashey/memoize-state)\n[![version-badge](https://img.shields.io/npm/v/memoize-state.svg?style=flat-square)](https://www.npmjs.com/package/memoize-state)\n[![npm downloads](https://img.shields.io/npm/dm/memoize-state.svg)](https://www.npmjs.com/package/react-focus-on)\n[![bundle size](https://img.shields.io/bundlephobia/minzip/memoize-state.svg)](https://bundlephobia.com/result?p=react-focus-on)\n[![Greenkeeper badge](https://badges.greenkeeper.io/theKashey/memoize-state.svg)](https://greenkeeper.io/)\n\n\n\u003eCaching (aka memoization) is very powerful optimization technique - however it only makes sense when maintaining the cache itself and looking up cached results is cheaper than performing computation itself again.\n[You don't need WASM to speed up JS](http://mrale.ph/blog/2018/02/03/maybe-you-dont-need-rust-to-speed-up-your-js.html)\n\n__Blazing fast usage-tracking based selection and memoization library__, which always works....\n\nRead me - [How I wrote the world’s fastest memoization library](https://dev.to/thekashey/how-i-wrote-the-world-s-fastest-memoization-library-34io)\n\n\n\n__Reselect__? Memoize-one? Most of memoization libraries remembers the parameters you provided, not what you did inside. \nSometimes is not easy to achive high cache hit ratio. Sometimes you have to _think_ about how to properly dissolve computation into the _memoizable_ parts.\n\n**I don't want to think how to use memoization, I want to use memoization!**\n\nMemoize-state is built to memoize more complex situations, even the ones which are faster to recompute, than to deside that recalculation is not needed.\nJust because one cheap computation can cause a redraw/reflow/recomputation cascade for a whole application.\n\nLets imagine some complex function.\n```js\n const fn = memoize(\n   (number, state, string) =\u003e ({result: state[string] + number})\n )\nlet firstValue = fn(1, { value: 1, otherValue   : 1 }, 'value'); // first call\n  firstValue === fn(1, { value: 1, otherValue   : 2 }, 'value'); // \"nothing\" changed\n  firstValue === fn(1, { value: 1, somethingElse: 3 }, 'value'); // \"nothing\" changed\n  firstValue !== fn(2, { value: 1, somethingElse: 3 }, 'value'); // something important changed\n```\nAll _ordinal_ memoization libraries will drop cache each time, as long `state` is different each time.\nMore of it - they will return a unique object each time, as long the function is returning a new object each time.\nBut not today!\n\nMemoize-state memoizes tracks used __state__ parts, using the same __magic__, as you can find in __MobX__ or __immer__.\nIt will know, that it should react only on some `state.value1` change, but not `value2`. _Perfect_.\n\nNow you able just to write functions AS YOU WANT. Memoize-state will detect all _really_ used arguments, variables and keys, and then - react only to the _right_ changes.\n\n[![NPM](https://nodei.co/npm/memoize-state.png?downloads=true\u0026stars=true)](https://nodei.co/npm/memoize-state/) \n\n## Implementations\n- [React-memoize](https://github.com/theKashey/react-memoize) - magic memoization for React, componentWillReceiveProps optimization, selection from context, whole SFC memoization.\n- [beautiful-react-redux](https://github.com/theKashey/beautiful-react-redux) - instant memoization for React-Redux\n- [why-did-you-update-redux](https://github.com/theKashey/why-did-you-update-redux) - selector quiality checker\n- [react-tracked](https://github.com/dai-shi/react-tracked) - React Context API made using the same principles.\n- your project!  \n\n# API\n* `memoizeState(function, options)` - creates memoized variant of a function.\n- Name, length (argument count), and any other own key will be transferred to memoized result\n- If argument is an object - memoize will perform `proxyequal` comparison, resulting true, of you did no access any object member\n- If argument is not an object - memoize will compare values.\n- result function will have `cacheStatistics` method. JFYI.\n\n### Possible options\n- `cacheSize`, default 1. The size of the cache.\n- `shallowCheck`, default true. Perform shallow equal between arguments.\n- `equalCheck`, default true. Perform deep proxyequal comparision.\n- `strictArity`, default false. Limit arguments count to the function default.\n- `nestedEquality`, default true. Keep the object equality for sub-proxies.\n- `safe`, default false. Activate the `safe` memoization mode. See below. \n\n### MapStateToProps\nYou know - it should be a __pure function__, returning the same results for the same arguments. \nmapStateToProps, should be strict equal across the different calls\n`mapStateToProps(state) === mapStateToProps(state)`\nor, at least, shallow equal\n`shallowEqual(mapStateToProps(state), mapStateToProps(state))`.\n\nCreating good memoization function, using reselect, avoiding side-effects - it could be hard. I know.\n\nMemoize-state was created to solve this case, especially this case.\n\n## Key principe\nMemoize-state will track the way you __USE__ the state.\n```js\n const state = {\n   branch1: {...},\n   branch2: {someKey1:1, someKey2: 2}\n }\n \n const aFunction = (state) =\u003e state.branch2.someKey2 \u0026\u0026 Math.random();\n \n const fastFunction = memoize(aFunction);\n \n```\nAfter the first launch memoize-state will detect the used parts of a state, and then react only for changes inside them\n```js\n const result1 = fastFunction(state); \n // result1 - some random. 42 for example\n const result2 = fastFunction({branch2: {someKey2:2}})\n // result2 - the same value! A new state is `proxyequal` to the old\n const result3 = fastFunction({branch2: {someKey2:3}})\n // result3 - is the NEW, at last.   \n```\n\n## Usage\n* Wrap mapStateToProps by `memoize`\n* Choose the memoization options (__unsafe__ by default).\n\n```js\nimport memoize from 'memoize-state';\n\nconst mapStateToProps = memoize((state, props) =\u003e {\n  //....\n});\n```\n\n#### Memoized composition\nYou can use compose(flow, flowRight) to pipe result from one memoized function to another. But better to use `flow`\n\n! All functions accepts __Object__ as input and return __Object as output.\n```js\nimport {memoizedFlow, memoizedFlowRight, memoizedPipe, memoizedCompose} from 'memoize-state';\n\n// memoizedFlow will merge result with the current input\n// thus you can not import and not return all the keys\n// and memoization will work\nconst sequence = memoizedFlow([\n  ({a,b}) =\u003e ({sumAB: a+b}),\n  ({a,c}) =\u003e ({sumAC: a+c}),\n  ({sumAB, sumAC}) =\u003e ({result: sumAB+sumAC})\n]);\n\nsequence({a:1, b:1, c:1}) === ({a:1, b:1, c:1, sumAB: 2, sumAC: 2, result: 4})\n\n//----------------\n\nimport flow from 'lodash.flow';\n\n// You have to rethrow all the variables you might need in the future\n// and memoization will not properly work, as long step2 will be regenerated then you will change b\n// as long it depends on sumAB from step1\nconst sequence = flow([\n  ({a,b, c}) =\u003e ({sumAB: a+b, a,c}),\n  ({a,c, sumAB}) =\u003e ({sumAC: a+c, sumAB}),\n  ({sumAB, sumAC}) =\u003e ({result: sumAB+sumAC})\n]);\n\nsequence({a:1, b:1, c:1}) === ({result: 4})\n```\n\n- `memoizedFlow` is equal to `memoizedPipe`, and applies functions from first to last.\n- `memoizedFlowRight` is equal to `memoizedCompose`, and applies functions from last to right(right).\n\n\n##### Additional API\nYou also could use memoize-state to double check your selectors.\n```js\nimport {shouldBePure} from 'memoize-state';\n\nconst mapStateToProps = shouldBePure((state, props) =\u003e {\n  //....\n});\n// then it will log all situations, when result was not shallow equal to the old one, but should.\n```\n`shouldBePure` will deactivate itself in `production` env. Use `shallBePure` if you need it always enabled.\n\n## You said UNSAFE???\nNot all functions could be `safely` memoized. Just not all of them.\nThe wrapped function __have to be pure__.\n```js\nlet cache = 0;\nconst func = (state) =\u003e (cache || cache = state.a);\nconst memoizedState = memoize(func);\nmemoizedState({a:1}); // will return 1 AND fill up the cache\nmemoizedState({a:2}); // will return 1 FROM cache, and dont read anything from state\nmemoizedState({a:3}); // memoize state saw, that you dont read anything from a state.\n// and will ignore __ANY__ changes. __FOREVER__!\n``` \n\u003e PS: this would not happened if state.a is a object. Memoize-state will understand the case, when you are returning a part of a state\n \nIt's easy to fix - `memoize(func, { safe: true })`, but func will be __called twice__ to detect internal memoization.\n\nIn case of internal memoization safe-memoize will deactivate itself.\n  \n\u003e Check performed only twice. Once on execution, and once on first cached result.\nIn both cases wrapped function should return the \"same\" result.   \n  \n### Can I memoize-state memoized-state function?\nYes, you could. \n\nBut memoize-state could disable another underlying memoizations libraries.\n  \n# Warning!\nNot everything is simple. Memoize-state works on copies of original object, __returning the original\nobject, if you have returned a copy__.\n\nThat means - if you get an array. __sort it__ and return result - you will return unsorted result.\n\n`Input has to be immutable`, don't sort it, don't mutate it, don't forget to Array.slice().\nbut you are the right person to watch over it.  \n  \n## Speed\n\nUses `ES6 Proxy` underneath to detect used branches of a state (as `MobX`).\nRemoves all the magic from result value. \nShould be slower than \"manual\" __reselect__ors, but faster than anything else.\n\nWe have a performance test, according to the results - \n- memoize-state __is not slower__ than major competitors, and __10-100x times faster__, for the \"state\" cases.\n- lodash.memoize and fast-memoize could not handle __big__ states as input.\n- memoize-one should be super fast, but it is not\n\nBut the major difference is\n- memoize-one are having __highest hitratio__, than means - it were able to \"memoize\" most of the cases\n```text\nfunction of 3 arguments, all unchanged\nbase            x           10230 ops/sec ±2.63% (5 runs sampled)  hitratio 0% 5700 /5700\nmemoize-one     x        24150462 ops/sec ±3.02% (6 runs sampled)  hitratio 100% 1 /14019795\nlodash.memoize  x         2954428 ops/sec ±4.02% (6 runs sampled)  hitratio 100% 1 /15818699\nfast-memoize    x         1065755 ops/sec ±3.22% (6 runs sampled)  hitratio 100% 1 /16243313\nmemoize-state   x         4910783 ops/sec ±2.55% (5 runs sampled)  hitratio 100% 1 /18929141\nFastest is memoize-one\n\nfunction of 1 arguments, object unchanged\nbase            x       408704195 ops/sec ±0.55% (5 runs sampled)  hitratio 100% 0 /188881067\nmemoize-one     x        77024718 ops/sec ±1.78% (6 runs sampled)  hitratio 100% 0 /221442642\nlodash.memoize  x         3776797 ops/sec ±1.55% (6 runs sampled)  hitratio 100% 0 /223654022\nfast-memoize    x        75375793 ops/sec ±3.08% (6 runs sampled)  hitratio 100% 0 /267664702\nmemoize-state   x         5690401 ops/sec ±3.77% (5 runs sampled)  hitratio 100% 0 /271589669\nFastest is base\n\nfunction of 1 arguments, object unchanged\nbase            x       398167311 ops/sec ±0.50% (6 runs sampled)  hitratio 100% 0 /190155405\nmemoize-one     x        76062398 ops/sec ±3.71% (6 runs sampled)  hitratio 100% 0 /231172341\nlodash.memoize  x         3734556 ops/sec ±6.70% (6 runs sampled)  hitratio 100% 0 /233243184\nfast-memoize    x        37234595 ops/sec ±2.30% (6 runs sampled)  hitratio 100% 0 /250419641\nmemoize-state   x          639290 ops/sec ±6.09% (6 runs sampled)  hitratio 100% 0 /250718787\nFastest is base\n\nfunction of 2 arguments, providing 3, all unchanged\nbase            x           10426 ops/sec ±3.01% (6 runs sampled)  hitratio 0% 3712 /3712\nmemoize-one     x        24164455 ops/sec ±6.67% (6 runs sampled)  hitratio 100% 1 /15190474\nlodash.memoize  x         2826340 ops/sec ±3.44% (6 runs sampled)  hitratio 100% 1 /16624930\nfast-memoize    x         1070852 ops/sec ±2.70% (6 runs sampled)  hitratio 100% 1 /17155394\nmemoize-state   x         4966459 ops/sec ±1.13% (5 runs sampled)  hitratio 100% 1 /19324311\nFastest is memoize-one\n\nfunction of 3 arguments, all changed / 10\nbase            x           10189 ops/sec ±3.13% (6 runs sampled)  hitratio 0% 3657 /3657\nmemoize-one     x           19842 ops/sec ±2.73% (6 runs sampled)  hitratio 63% 5316 /14288\nlodash.memoize  x           33160 ops/sec ±1.45% (5 runs sampled)  hitratio 83% 5782 /33561\nfast-memoize    x           19029 ops/sec ±6.04% (5 runs sampled)  hitratio 86% 6731 /47024\nmemoize-state   x           18527 ops/sec ±10.56% (5 runs sampled)  hitratio 93% 3868 /54760\nFastest is lodash.memoize\n\nfunction with an object as argument, returning a part\nbase            x           10095 ops/sec ±3.49% (5 runs sampled)  hitratio 0% 4107 /4107\nmemoize-one     x           10054 ops/sec ±3.14% (6 runs sampled)  hitratio 50% 4141 /8249\nlodash.memoize  x         1695449 ops/sec ±3.68% (6 runs sampled)  hitratio 100% 1 /950379\nfast-memoize    x         1287216 ops/sec ±1.29% (6 runs sampled)  hitratio 100% 1 /1590863\nmemoize-state   x         1574688 ops/sec ±2.24% (6 runs sampled)  hitratio 100% 1 /2469327\nFastest is lodash.memoize\n\nfunction with an object as argument, changing value, returning a part\nbase            x           10187 ops/sec ±1.66% (6 runs sampled)  hitratio 0% 4179 /4179\nmemoize-one     x           10205 ops/sec ±3.96% (6 runs sampled)  hitratio 50% 4174 /8354\nlodash.memoize  x           87943 ops/sec ±12.70% (5 runs sampled)  hitratio 92% 4138 /49727\nfast-memoize    x           90510 ops/sec ±1.05% (6 runs sampled)  hitratio 96% 3972 /89439\nmemoize-state   x           76372 ops/sec ±6.67% (6 runs sampled)  hitratio 97% 3612 /125554\nFastest is fast-memoize,lodash.memoize\n\nfunction with an object as argument, changing other value, returning a part\nbase            x            9867 ops/sec ±7.72% (5 runs sampled)  hitratio 0% 4537 /4537\nmemoize-one     x           10066 ops/sec ±4.24% (5 runs sampled)  hitratio 47% 5059 /9597\nlodash.memoize  x           92596 ops/sec ±0.61% (6 runs sampled)  hitratio 92% 4515 /54745\nfast-memoize    x           89224 ops/sec ±1.24% (5 runs sampled)  hitratio 96% 3445 /89181\nmemoize-state   x         1469865 ops/sec ±2.95% (5 runs sampled)  hitratio 100% 1 /805990\nFastest is memoize-state\n\nfunction with 2 objects as argument, changing both value\nbase            x           10127 ops/sec ±2.21% (5 runs sampled)  hitratio 0% 5489 /5489\nmemoize-one     x           10030 ops/sec ±3.97% (6 runs sampled)  hitratio 60% 3702 /9192\nlodash.memoize  x            9745 ops/sec ±4.69% (6 runs sampled)  hitratio 70% 3997 /13190\nfast-memoize    x            9268 ops/sec ±5.04% (5 runs sampled)  hitratio 77% 3855 /17046\nmemoize-state   x           63493 ops/sec ±6.49% (6 runs sampled)  hitratio 94% 2736 /44395\nFastest is memoize-state\n\nwhen changes anything, except the function gonna to consume\nbase            x            9901 ops/sec ±3.78% (6 runs sampled)  hitratio 0% 5121 /5121\nmemoize-one     x           10087 ops/sec ±2.59% (6 runs sampled)  hitratio 57% 3914 /9036\nlodash.memoize  x            9643 ops/sec ±1.25% (6 runs sampled)  hitratio 67% 4361 /13398\nfast-memoize    x            9554 ops/sec ±1.13% (6 runs sampled)  hitratio 76% 4228 /17627\nmemoize-state   x          520442 ops/sec ±1.54% (5 runs sampled)  hitratio 100% 1 /270727\nFastest is memoize-state\n\nwhen state is very big, and you need a small part\nbase            x           10097 ops/sec ±1.63% (6 runs sampled)  hitratio 0% 4428 /4428\nmemoize-one     x            9262 ops/sec ±6.27% (5 runs sampled)  hitratio 53% 3974 /8403\nlodash.memoize  x             276 ops/sec ±3.31% (6 runs sampled)  hitratio 100% 12 /8516\nfast-memoize    x             280 ops/sec ±4.77% (6 runs sampled)  hitratio 100% 10 /8615\nmemoize-state   x           83005 ops/sec ±6.47% (6 runs sampled)  hitratio 92% 4042 /49019\nFastest is memoize-state\n``` \n\n### Even more speed\n\n```js\nfunction fn1(object) {\n  return object.value\n}\n\n// ^^ memoize state will react to any change of .value\n\nfunction fn2(object) {\n  return {...object.value}\n}\n\n// ^^ memoize state will react to any change of the values inside the .value\n\n// for example, if value contain booleans the X and they Y - they form 4 possible pairs\nconst superMemoize = memoize(fn2, { cacheSize: 4 });\n\n// ^^ you just got uber function, which will return 4 exactly the same objects\n```\n\n## The cost of the magic\nExecuting the function against EMPTY function, but triggering most of internal mechanics.\n```text\nbase            x       244.000.431 \nmemoize-one     x        18.150.966 \nlodash.memoize  x         3.941.183 \nfast-memoize    x        34.699.858 \nmemoize-state   x         4.615.104 \n```\n\u003e this 4 millions operations per second? A bit more that enough\n\n## The common memoization\nMemoize-state is not a best fit for a common case. It is designed to handle\n- the complex objects\n- limited count of stored cache lines (default: 1)\n\nThis is a fibonacci test from - fast-memoize. The test uses different performance measuring tool\nand numbers differs.\n```test\n│ fast-memoize@current       │ 204,819,529 │ ± 0.85%                  │ 88          │\n├────────────────────────────┼─────────────┼──────────────────────────┼─────────────┤\n│ lru-memoize (single cache) │ 84,862,416  │ ± 0.59%                  │ 93          │\n├────────────────────────────┼─────────────┼──────────────────────────┼─────────────┤\n│ iMemoized                  │ 35,008,566  │ ± 1.29%                  │ 90          │\n├────────────────────────────┼─────────────┼──────────────────────────┼─────────────┤\n│ lodash                     │ 24,197,907  │ ± 3.70%                  │ 82          │\n├────────────────────────────┼─────────────┼──────────────────────────┼─────────────┤\n│ underscore                 │ 17,308,464  │ ± 2.79%                  │ 87          │\n├────────────────────────────┼─────────────┼──────────────────────────┼─────────────┤\n│ memoize-state \u003c\u003c----       │ 17,175,290  │ ± 0.80%                  │ 87          │\n├────────────────────────────┼─────────────┼──────────────────────────┼─────────────┤\n│ memoizee                   │ 12,908,819  │ ± 2.60%                  │ 78          │\n├────────────────────────────┼─────────────┼──────────────────────────┼─────────────┤\n│ lru-memoize (with limit)   │ 9,357,237   │ ± 0.47%                  │ 91          │\n├────────────────────────────┼─────────────┼──────────────────────────┼─────────────┤\n│ ramda                      │ 1,323,820   │ ± 0.54%                  │ 92          │\n├────────────────────────────┼─────────────┼──────────────────────────┼─────────────┤\n│ vanilla                    │ 122,835     │ ± 0.72%                  │ 89          │\n└────────────────────────────┴─────────────┴──────────────────────────┴─────────────┘\n```\nmemoize-state is comparable with lodash and underscore, even in this example.\n\n## Spread no-op\n\u003ememoize-state: object spread detected in XXX. Consider refactoring.\n\nMemoize state could not properly work if you \"spread\" state\n```js\nconst mapStateToProps = ({prop,i,need,...rest}) =\u003e....\n//or\nconst mapStateToProps = (state, props) =\u003e ({ ...state, ...props })\n//or\nconst mapState = ({ page, direction, ...state }) =\u003e ({\n  page,\n  direction,\n  isLoading: isLoading(state)\n})\n``` \nIt will assume, that you need ALL the keys, meanwhile - you could not.\n\nWorkaround - refactor the code\n```js\nconst mapState = state =\u003e ({\n  page: state.page,\n  direction: state.direction,\n  isLoading: isLoading(state)\n})\n```\n\nSee [issue](https://github.com/theKashey/memoize-state/issues/3#issuecomment-372226092) for more details\n\n## Compatibility\n\nIE11/Android compatible. Contains [proxy-polyfill](https://github.com/GoogleChrome/proxy-polyfill) inside.\n\n# Licence\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthekashey%2Fmemoize-state","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthekashey%2Fmemoize-state","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthekashey%2Fmemoize-state/lists"}