{"id":13450339,"url":"https://github.com/megazazik/react-cached-callback","last_synced_at":"2025-07-04T05:03:11.394Z","repository":{"id":27923618,"uuid":"115587427","full_name":"megazazik/react-cached-callback","owner":"megazazik","description":"Functions for caching many callbacks by key, for example, in loops.","archived":false,"fork":false,"pushed_at":"2024-06-22T13:32:05.000Z","size":1773,"stargazers_count":10,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-11-11T21:43:01.592Z","etag":null,"topics":[],"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/megazazik.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2017-12-28T05:13:34.000Z","updated_at":"2022-04-02T10:50:30.000Z","dependencies_parsed_at":"2024-01-07T18:05:50.799Z","dependency_job_id":"8adb51f6-dcb8-4099-ac9c-9eb7a545c156","html_url":"https://github.com/megazazik/react-cached-callback","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/megazazik%2Freact-cached-callback","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/megazazik%2Freact-cached-callback/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/megazazik%2Freact-cached-callback/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/megazazik%2Freact-cached-callback/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/megazazik","download_url":"https://codeload.github.com/megazazik/react-cached-callback/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227657565,"owners_count":17799984,"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":[],"created_at":"2024-07-31T07:00:33.740Z","updated_at":"2024-12-02T02:16:05.123Z","avatar_url":"https://github.com/megazazik.png","language":"TypeScript","funding_links":[],"categories":["Packages"],"sub_categories":[],"readme":"# react-cached-callback\n\n[![npm version](https://badge.fury.io/js/react-cached-callback.svg)](https://badge.fury.io/js/react-cached-callback)\n\n`react-cached-callback` is a helper to remove arrow-functions and bind from cycles in `react` component's `render` method.\n\nThis package containes the following helpers:\n* [cached](#cached) decorator ([makeCached](#makecached))\n* [useGetCallback](#usegetcallback)\n* [useEventCallback](#useeventcallback)\n* [useGetEventCallback](#usegeteventcallback)\n\nExample with `cached`:\n```javascript\nimport cached from 'react-cached-callback';\n\nclass SomeComponent extends React.Component {\n\t@cached\n\t_onClick(index) {\n\t\treturn () =\u003e doSomething(index);\n\t}\n\n\trender() {\n\t\treturn (\n\t\t\t\u003cdiv\u003e\n\t\t\t\t{someArray.map((obj, index) =\u003e (\n\t\t\t\t\t\u003cChildComponent onClick={this._onClick(index)} /\u003e\n\t\t\t\t))}\n\t\t\t\u003c/div\u003e\n\t\t);\n\t}\n}\n```\n\nExample with `useGetCallback`:\n```javascript\nimport { useGetCallback } from 'react-cached-callback';\n\nfunction SomeComponent ({someProp}) {\n\tconst getOnClick = useGetCallback(\n\t\t(index) =\u003e () =\u003e {\n\t\t\tdoSomething(index, someProp);\n\t\t},\n\t\t[someProp]\n\t);\n\t\n\treturn (\n\t\t\u003cdiv\u003e\n\t\t\t{someArray.map((obj, index) =\u003e (\n\t\t\t\t\u003cChildComponent onClick={getOnClick(index)} /\u003e\n\t\t\t))}\n\t\t\u003c/div\u003e\n\t);\n}\n```\n\n## Why?\nIt is not recomended to create new functions in each `render` function call in `react` and pass them to child components. That is because of performance optimization reasons. Performance decrease can happen when you use arrow-function or bind in `render` function. Usualy you can easy avoid this by creating a component's property with an arrow-function:\n```javascript\nclass SomeComponent extends React.Component {\n\t_onClickHandler = () =\u003e {\n\t\t...\n\t}\n\n\trender() {\n\t\treturn (\n\t\t\t\u003cdiv \u003e\n\t\t\t\t\u003cChildComponent onClick={this._onClickHandler} /\u003e\n\t\t\t\u003c/div\u003e\n\t\t);\n\t}\n}\n```\nBut sometimes you need to pass `onClickHandler` to a number of components in cycle. And `onClickHandler` needs to know an elements's index when it is executed.\n`react-cached-callback` will help you to resolve this issue easy.\n\n## @cached\n\n### How it works\nTo use `cached` you need to add into a component a method  which creates callbacks for each component rendered in cycle. Then you need to decorate it with `cached`. For example:\n```javascript\n@cached\n_createOnClick(index) {\n\treturn () =\u003e doSomething(index);\n}\n\nrender() {\n\treturn (\n\t\t\u003cdiv\u003e\n\t\t\t{someArray.map((obj, index) =\u003e (\n\t\t\t\t\u003cChildComponent onClick={this._createOnClick(index)} /\u003e\n\t\t\t))}\n\t\t\u003c/div\u003e\n\t);\n}\n```\nWhen `_createOnClick` is called with some index for the first time `cached` saves a callback returned by original `_createOnClick`, creates a wrapper for it and returns the wrapper.  \nWhen `_createOnClick` is called with the same index next time `cached` gets a new callback from the original `_createOnClick`, save it and returns the wrapper which was created earlier. When the wrapper is called it calls a callback which was returned by original `_createOnClick` last time.\n\nTo determine a wrapper which should be returned `cached` uses a *key*. In the example above the first parameter (`index`) is used as a key. You can specify an other key. See *Parameters* section for more details.\n\n### Parameters\nThe `cached` decorator can be used with one parameter or without it. This parameter can be an object, a number or a function.\n```javascript\n// with object with parameters\n@cached({index: 1, pure: false})\n\n// with number\n@cached(1)\n\n// with function\n@cached((obj) =\u003e obj.id)\n\n// without parameters\n@cached\n//or\n@cached()\n```\n\nYou can pass the following parameters to `cached`:\n* *index* (number) - index of an parameter which will be used as a key\n* *getKey* (function) - function to calculate a key. It cannot be used with *index*.\n* *pure* (boolean) - if *pure* is true `cached` will not call the original method to get a callback if it is called with the same parameters next time.\n\n#### no parameters\nIf `cached` is used without parameters the first parameter is used as a key:\n```javascript\n@cached\n_onClick(index) {\n\treturn () =\u003e doSomething(index);\n}\n\nrender() {\n\treturn (\n\t\t\u003cdiv\u003e\n\t\t\t{someArray.map((obj, index) =\u003e (\n\t\t\t\t\u003cChildComponent onClick={this._onClick(index)} /\u003e\n\t\t\t))}\n\t\t\u003c/div\u003e\n\t);\n}\n```\n`index` is used as a key here. If `_onClick` is called with the same index next time the same wrapper will be returned.\n\n#### index\nYou can use any parameter as a key by specifying a parameter's index\n```javascript\n@cached({index: 1})\n// or \n@cached(1)\n_onClick(obj, index) {\n\treturn () =\u003e doSomething(obj);\n}\n\nrender() {\n\treturn (\n\t\t\u003cdiv\u003e\n\t\t\t{someArray.map((obj, index) =\u003e (\n\t\t\t\t\u003cChildComponent onClick={this._onClick(obj, index)} /\u003e\n\t\t\t))}\n\t\t\u003c/div\u003e\n\t);\n}\n```\n\n#### getKey\nYou can specify a function to calculate a key using passed parameters:\n```javascript\n@cached((obj) =\u003e obj.id)\n// or\n@cached({getKey: (obj) =\u003e obj.id})\n_onClick(obj) {\n\treturn () =\u003e doSomething(obj);\n}\n\nrender() {\n\treturn (\n\t\t\u003cdiv\u003e\n\t\t\t{someArray.map((obj) =\u003e (\n\t\t\t\t\u003cChildComponent onClick={this._onClick(obj)} /\u003e\n\t\t\t))}\n\t\t\u003c/div\u003e\n\t);\n}\n```\nThe `getKey` gets the same parameters as the original method. In this case the `getKey` will get one parameter - `obj`, and the obj's id will be used as a key.  \nIf `getKey` is passed to `@cached` then the `index` parameter is ignored.\n\n#### pure\nWhen a wrapper is called with all the same parameters in the next time it does not call the original `_onClick` function and used cached result. If at least one parameter is changed the original `_onClick` is called.\nIf you need to call the original `_onClick` each time you can specify a `pure` parameter to `false`:\n```javascript\n@cached({pure: false})\n_onClick(obj) {\n\treturn () =\u003e doSomething(obj);\n}\n```\n\n### makeCached\nif you cannot use decorators you can use a helper function `makeCached`. It has the follofing interface:  \nmakeCached(component: object, methodName: string, params?: object)  \n\n* *component* - react component class (or some other class)\n* *methodName* - method's name which should be cached\n* *params* - the same parameters which the `cached` decorator gets\n\n#### without parameters\n```javascript\nimport { makeCached } from 'react-cached-callback';\n\nclass SomeComponent extends React.Component {\n\t_onClick(index) {\n\t\treturn () =\u003e doSomething(index);\n\t}\n\n\trender() {\n\t\treturn (\n\t\t\t\u003cdiv\u003e\n\t\t\t\t{someArray.map((obj, index) =\u003e (\n\t\t\t\t\t\u003cChildComponent onClick={this._onClick(index)} /\u003e\n\t\t\t\t))}\n\t\t\t\u003c/div\u003e\n\t\t);\n\t}\n}\n\nmakeCached(SomeComponent, '_onClick');\n```\n\n#### index\n```\nmakeCached(SomeComponent, '_onClick', {index: 1});\n// or \nmakeCached(SomeComponent, '_onClick', 1);\n```\n\n#### getKey\n```\nmakeCached(SomeComponent, '_onClick', {getKey: (obj) =\u003e obj.id});\n// or \nmakeCached(SomeComponent, '_onClick', (obj) =\u003e obj.id);\n```\n\n#### pure\n```\nmakeCached(SomeComponent, '_onClick', {pure: false);\n```\n\n## useGetCallback\nThe `useGetCallback` hook is similar to react's `useCallback` hook, but `useGetCallback` helps to create several callbacks in cycles.\n\n```javascript\nimport { useGetCallback } from 'react-cached-callback';\n\nfunction SomeComponent ({someProp}) {\n\tconst getOnClick = useGetCallback(\n\t\t(obj) =\u003e () =\u003e {\n\t\t\tdoSomething(obj, someProp);\n\t\t},\n\t\t(obj) =\u003e obj.id,\n\t\t[someProp]\n\t);\n\t\n\treturn (\n\t\t\u003cdiv\u003e\n\t\t\t{someArray.map((obj) =\u003e (\n\t\t\t\t\u003cChildComponent onClick={getOnClick(obj)} /\u003e\n\t\t\t))}\n\t\t\u003c/div\u003e\n\t);\n}\n```\n\nAfter each render `useGetCallback` saves created callbacks and return them during next render. To determine which callback should be returned `useGetCallback` uses a *key*. By default the first parameter is used as a key. An object's id  is used as a key in the example above.\n\nYou can pass the following parameters to `useGetCallback`:\n* *getCallback* (function) - this function should return a callback.\n* *keyIndex* (number) or *getKey* (function) *optional* - index of a parameter which should be used as a key or a function which should return a key. The `getKey` function gets all the same parameters as the function which creates callbacks.\n* *dependencies* (array) *optional* - values which are used in callback. It is similar to dependencies of react's `useCallback`.\n\n`useGetCallback` returns a new callback for some key each time when one of dependencies or call parameters (`callParams` in the example below) are changed.\n\n```javascript\nconst getCallback = useGetCallback(\n\t(...callParams) =\u003e {\n\t\treturn () =\u003e doSomething(...callParams)\n\t},\n\tdependencies\n);\n```\n\n## useEventCallback\nThe `useEventCallback` hook can be used as the react's `useCallback` to create only one callback. But unlike the `useCallback` the `useEventCallback` doesn't create a new callback when any dependencies are changed. It always returns the same function.\n\nThe `useEventCallback` gets only one parameter - a callback.\n\n```javascript\nconst callback = useEventCallback(\n\t(callParams) =\u003e { doSomething(...callParams) }\n);\n```\n\nThe `useEventCallback` always returns the same function so rendering process is more optimized because children components can rerender less often. But this can be a reason of bugs in async mode. So you should not use such callbacks early then rendering is finished. You can use them on UI events like `onClick`, `onHover` and after render - in `useEffect`. Using them during `useLayoutEffect` or `componentDidMount` / `componentDidUpdate` also can be causing bugs.\n\n## useGetEventCallback\n`useGetEventCallback` can be used to create many callback in cycles as `useGetCallback`. But it doesn't create a new callback when any dependencies or parameters changes. As `useEventCallback` you should not use callbacks created by `useGetEventCallback` before render finishes.\n\nYou can pass the following parameters to `useGetEventCallback`:\n* *getCallback* (function) - this function should return a callback.\n* *keyIndex* (number) or *getKey* (function) *optional* - index of a parameter which should be used as a key or a function which should return a key. By default the first paramether is used as a key. The `getKey` function gets all the same parameters as the function which creates callbacks.\n\n```javascript\nconst getOnClick = useGetEventCallback(\n\t(obj) =\u003e {\n\t\treturn () =\u003e doSomething(obj)\n\t},\n\t(obj) =\u003e obj.id\n);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmegazazik%2Freact-cached-callback","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmegazazik%2Freact-cached-callback","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmegazazik%2Freact-cached-callback/lists"}