{"id":13394104,"url":"https://github.com/theKashey/react-memoize","last_synced_at":"2025-03-13T19:31:58.896Z","repository":{"id":49798006,"uuid":"122186385","full_name":"theKashey/react-memoize","owner":"theKashey","description":"🧠 React memoization library we all deserve","archived":false,"fork":false,"pushed_at":"2020-05-30T10:56:03.000Z","size":3512,"stargazers_count":129,"open_issues_count":21,"forks_count":4,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-05-16T19:01:52.227Z","etag":null,"topics":["memoize","optimization","react","renderprops"],"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-20T10:53:00.000Z","updated_at":"2024-04-04T16:03:06.000Z","dependencies_parsed_at":"2022-09-14T11:42:21.647Z","dependency_job_id":null,"html_url":"https://github.com/theKashey/react-memoize","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theKashey%2Freact-memoize","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theKashey%2Freact-memoize/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theKashey%2Freact-memoize/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theKashey%2Freact-memoize/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/theKashey","download_url":"https://codeload.github.com/theKashey/react-memoize/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243469244,"owners_count":20295715,"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":["memoize","optimization","react","renderprops"],"created_at":"2024-07-30T17:01:09.100Z","updated_at":"2025-03-13T19:31:58.045Z","avatar_url":"https://github.com/theKashey.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ch1\u003ereact-memoize  🤯 🧠\u003c/h1\u003e\n  \u003cbr/\u003e\n  \u003cimg src=\"./assets/logo.png\" alt=\"memoize\" height=\"187\" align=\"center\"\u003e\n  \u003cbr/\u003e\n  \u003cbr/\u003e\n  \u003ca href=\"https://circleci.com/gh/theKashey/react-memoize/tree/master\"\u003e\n     \u003cimg src=\"https://img.shields.io/circleci/project/github/theKashey/react-memoize/master.svg?style=flat-square)\" alt=\"Build status\"\u003e\n  \u003c/a\u003e\n  \n  \u003ca href=\"https://codecov.io/github/thekashey/react-memoize\"\u003e\n   \u003cimg src=\"https://img.shields.io/codecov/c/github/thekashey/react-memoize.svg?style=flat-square\" /\u003e\n  \u003c/a\u003e\n    \n  \u003ca href=\"https://www.npmjs.com/package/react-memoize\"\u003e\n   \u003cimg src=\"https://img.shields.io/npm/v/react-memoize.svg?style=flat-square\" /\u003e\n  \u003c/a\u003e\n  \n  \u003ca href=\"https://greenkeeper.io/\"\u003e\n     \u003cimg src=\"https://badges.greenkeeper.io/theKashey/react-memoize.svg\" /\u003e\n  \u003c/a\u003e\n  \n  \u003cbr/\u003e\n  \u003cbr/\u003e\n  \u003cbr/\u003e  \n\u003c/div\u003e  \n\n7kb MobX-level memoization library, which tracks all the arguments you are __really__ depends on.\n- It is not so fast, as reselect, but could handle more cases, and works out of the box. \n- It is not so fast, but much faster, than _VDOM tree comparison_ you will face in case of render trashing.  \n- It contain 3 types of memoziation to handle all possible cases.\n\nUses [memoize-state](https://github.com/theKashey/memoize-state) underneath, providing the same magic for `get` as [immer](https://github.com/mweststrate/immer) provided to `set`. \n\nWorks fine in all browsers including IE11.\n\n__Just write code as you want. It it will be properly memoized__.\n\nThis is declarative component memoization for React! Based on [Dan Abramov's tweet](https://twitter.com/dan_abramov/status/965378278461755392)\nCould change the way you did `componentWillReceiveProps`, could replace `getDerivedStateFromProps`, could make things better.\n\n\u003e IE11+, React 15 and React 16.3 compatible.\n\n- [Memoize](#memoize) - to create declarative memoized selection.\n- [MemoizedFlow](#flow) - to create declarative memoized flow.\n- [MemoizeContext](#memoizecontext) - to create memoized selector from context(or any Consumer).\n- [MemoizedRender](#memoizedrender) - to create a render, memoized by a value provided. \n\nMemoize, MemoizedFlow, MemoizeContext accepts one or more functions to select or transform incoming data, and provide result to a function-as-child.\n\nMemoizedRender is memoizing the function-as-child itself.\n\n\u003e What is the difference between React-memoize and React.memo? Memo is a \"PureComponent\", Memoize is more about \naccurate memoization based on the real props consumption.\nReact-memoize is about \"calculation\" memoization\n\n### Memoize\n\n```js\n import Memoize from 'react-memoize';\n \n \u003cMemoize\n   prop1 = \"theKey\"\n   state = {this.state}\n   // values from above will be provided to compute function\n   compute={({prop1, state}) =\u003e heavyComputation(state[prop1])} // Memoize tracks WHAT you are doing \n   pure // Memoize will be a pure component itself\n  \u003e\n  { result =\u003e \u003cDisplay\u003e{result}\u003c/Display\u003e}\n  \u003c/Memoize\u003e\n```\nThere is only __one prop__ - `compute`, all others will be passed inside.\nMemoize get `compute` function, add passes all the other props to it, streaming result to the render prop.\n\nIf `pure` prop is set ReactMemoize wil behave as PureComponent, and not update children when could not. \n\n## Flow\n`getDerivedStateFromProps` gives you ability to derive a new state from props, while `componentDidUpdate` enables you to react \nto the state changes.\n\n__MemoizedFlow__ is `getDerivedStateFromState`. Following example react to the state changes, allowing \nto change ordering of rows and applies a pagination.\n\n\"The Flow\" is safe and performant way to form something from something, and rebuilt then the time calls.\n```js\nimport {MemoizedFlow} from 'react-memoize';\n\nclass SortablePageableTable extends Component {\n    state = {\n    page:0,\n    perPage:10,\n    filter: I =\u003e I\n    };\n    \n    onSortChange = (order) =\u003e this.setState(order)\n    onPageChange = page =\u003e this.setState(page);\n    \n    render () {\n    return (\n          \u003cMemoizedFlow \n          input={{...this.props, ...this.state}}\n          flow={[\n            // will react on rows or filter change\n            ({rows, filter}) =\u003e ({rows: list.filter(filter)}),\n            // will react on rows(from step1) change or order\n            ({rows, order}) =\u003e ({rows: list.slice().sort(order)}), // !! clone array before sort\n            // will react on rows and pagination changes\n            ({rows, page, perPage}) =\u003e ({rows: list.slice(page*perPage, (page+1)*perPage)}),\n            // will react on something else, not related\n            ({rain, bows}) =\u003e ({rainbows: rain+bows, rain: null, bows: null })\n            ]}\n          \u003e\n            {output =\u003e \u003cTable {...output} onSortChange={this.onSortChange} onPageChange={this.onPageChange}/\u003e}\n          \u003c/MemoizedFlow\u003e\n    }\n}\n\n\u003cSortablePageableTable rows = {tableRows} /\u003e\n```\nFirst step is getting `input`, and each following is reading from a value provided before, spreading\nown result over it. Until the last step will be reached, and output will be provided to render prop.\n\nEach step is memoized, as usual, and will always reuse value from the steps before. \n\n### MemoizeContext\nReact memoize also provides component to __select__ and __memoize__ data from React16 context, or any other component \nwhich will pass some values into renderProp.\n\n```js\nimport {MemoizeContext} from 'react-memoize';\n\n\u003cContext.Provider value={{prop1: 1, prop2: 2, prop3: 3}}\u003e\n    \u003cMemoizeContext consumer={Context.Consumer} selector={select}\u003e\n      {values =\u003e \u003cRender {...values} /\u003e}\n    \u003c/MemoizeContext\u003e\n\u003c/Context.Provider\u003e\n``` \n`consumer` could be any \"context\"-compatible Component - React.context, create-react-context, unstated, react-copy-write.\nAll the additional props will be passed down to consumer. \n\nIt is better to explain using example.\n```js\n\u003cMemoizeContext consumer={Consumer} prop1={1} anotherProp={3} selector={select}\u003e /\u003e\n\n// will result\n\n\u003cConsumer prop1={1} anotherProp={3}\u003e\n{ contextValues =\u003e \u003cReactMemoize {...contextValues} compute={selector}\u003e...\u003c/ReactMemoize\u003e}\n\u003c/Consumer\u003e\n```\n\nThis is like Redux without dispatching. State in context, selector aka mapStateToProps, and magic memoization in between.\n\n__See it in action -\u003e__ https://codesandbox.io/s/xjz5y3wzrz 🛠\n\n# MemoizedRender\nMemoizedRender is mostly usable with Context API\n```js\nimport {MemoizedRender} from 'react-memoize';\n\n\u003cContext.Provider value={{prop1: 1, prop2: 2, prop3: 3}}\u003e\n    \u003cMemoizedRender consumer={Context.Consumer}\u003e\n      {values =\u003e \u003cRender {...select(values)} /\u003e}\n    \u003c/MemoizedRender\u003e\n\u003c/Context.Provider\u003e\n```\nOr, the better example (from [react-copy-write](https://github.com/aweary/react-copy-write#consuming-state))\n```js\nconst UserAvatar = ({ id }) =\u003e (\n  \u003cMemoizedRender consumer={State.Consumer}\u003e\n    {state =\u003e (\n      \u003cdiv className=\"avatar\"\u003e\n        \u003cimg src={state.users[id].avatar.src} /\u003e\n      \u003c/div\u003e\n    )}\n  \u003c/MemoizedRender\u003e\n);\n```\nWhile `react-copy-write` declares that _ The problem with this is that whenever any value in state changes, UserAvatar will be re-rendered, even though it's only using a single property from a single, nested object._\nThis example will work, as long MemoizedRender will track used keys, and perform update only when necessary.\n\nIt is also possible to provide `value` as a prop\n```js\n\u003cMemoizedRender value={originalValue}\u003e\n  {values =\u003e \u003cRender {...select(values)} /\u003e}\n\u003c/MemoizeContext\u003e\n```\n\nMemoizedRender __memoizes \"render\" as a whole__. This is __absolute pure component__. Be carefull. Might be not 100% compatible with async rendering\nif you pass values you were provided down the tree, as long __async accessed keys are not tracked__.\nThus - MemoizedRender may not react to changes in them.\n\n## About\n\nReact-memoize uses [memoize-state](https://github.com/theKashey/memoize-state) underneath to perform __MobX__ like memozation\nand achive the maximal minimal level of memoization cache misses. Sounds a bit strange, but this mean - react-memoize will try to preserve the current `state` at all costs. From 10% to 50% \"more\" in comparison.\n\n\u003e In all the cases only ONE! result is memoized. The goal of the component is to cut off updates.\n\nFor example:\n\n- recomputation will be made only when stateSubKey is changed\n```js\n \u003cMemoize\n   state = {this.state}   \n   compute={({state}) =\u003e soSomethingWith(state.stateSubKey)}\n  \u003e\n  { result =\u003e ....}\n  \u003c/Memoize\u003e\n``` \n- recomputation will be made only when used prop is changed\n```js\n \u003cMemoize\n   usedProp = {1}   \n   unusedProp = {2}\n   compute={({usedProp}) =\u003e soSomethingWith(usedProp)}\n  \u003e\n  { result =\u003e ....}\n  \u003c/Memoize\u003e\n``` \n- recomputation will be make only when item count changes, value of any item or text of items __passed__ thought the filter.\n```js\n \u003cMemoize\n   list = {this.state.list}   \n   compute={({list}) =\u003e list.filter(item =\u003e item.value).map(item =\u003e item.text)}\n  \u003e\n  { result =\u003e ....}\n  \u003c/Memoize\u003e\n``` \n\nThe same magic as in [beautiful-react-redux](https://github.com/theKashey/beautiful-react-redux), kudos to `memoize-state` library.\n\nPS: For systems without Proxy support memoize will use [memoize-one](https://github.com/alexreardon/memoize-one)\n\n\n# Licence\n MIT\n \n \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FtheKashey%2Freact-memoize","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FtheKashey%2Freact-memoize","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FtheKashey%2Freact-memoize/lists"}