
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
react-cached-callback
Advanced tools
Library for excluding function generations on React's render function call
react-cached-callback is a helper to remove arrow-functions and bind from cycles in react component's render method.
This package containes the following helpers:
Example with cached:
import cached from 'react-cached-callback';
class SomeComponent extends React.Component {
@cached
_onClick(index) {
return () => doSomething(index);
}
render() {
return (
<div>
{someArray.map((obj, index) => (
<ChildComponent onClick={this._onClick(index)} />
))}
</div>
);
}
}
Example with useGetCallback:
import { useGetCallback } from 'react-cached-callback';
function SomeComponent ({someProp}) {
const getOnClick = useGetCallback(
(index) => () => {
doSomething(index, someProp);
},
[someProp]
);
return (
<div>
{someArray.map((obj, index) => (
<ChildComponent onClick={getOnClick(index)} />
))}
</div>
);
}
It 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:
class SomeComponent extends React.Component {
_onClickHandler = () => {
...
}
render() {
return (
<div >
<ChildComponent onClick={this._onClickHandler} />
</div>
);
}
}
But 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.
react-cached-callback will help you to resolve this issue easy.
To 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:
@cached
_createOnClick(index) {
return () => doSomething(index);
}
render() {
return (
<div>
{someArray.map((obj, index) => (
<ChildComponent onClick={this._createOnClick(index)} />
))}
</div>
);
}
When _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.
When _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.
To 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.
The cached decorator can be used with one parameter or without it. This parameter can be an object, a number or a function.
// with object with parameters
@cached({index: 1, pure: false})
// with number
@cached(1)
// with function
@cached((obj) => obj.id)
// without parameters
@cached
//or
@cached()
You can pass the following parameters to cached:
cached will not call the original method to get a callback if it is called with the same parameters next time.If cached is used without parameters the first parameter is used as a key:
@cached
_onClick(index) {
return () => doSomething(index);
}
render() {
return (
<div>
{someArray.map((obj, index) => (
<ChildComponent onClick={this._onClick(index)} />
))}
</div>
);
}
index is used as a key here. If _onClick is called with the same index next time the same wrapper will be returned.
You can use any parameter as a key by specifying a parameter's index
@cached({index: 1})
// or
@cached(1)
_onClick(obj, index) {
return () => doSomething(obj);
}
render() {
return (
<div>
{someArray.map((obj, index) => (
<ChildComponent onClick={this._onClick(obj, index)} />
))}
</div>
);
}
You can specify a function to calculate a key using passed parameters:
@cached((obj) => obj.id)
// or
@cached({getKey: (obj) => obj.id})
_onClick(obj) {
return () => doSomething(obj);
}
render() {
return (
<div>
{someArray.map((obj) => (
<ChildComponent onClick={this._onClick(obj)} />
))}
</div>
);
}
The 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.
If getKey is passed to @cached then the index parameter is ignored.
When 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.
If you need to call the original _onClick each time you can specify a pure parameter to false:
@cached({pure: false})
_onClick(obj) {
return () => doSomething(obj);
}
if you cannot use decorators you can use a helper function makeCached. It has the follofing interface:
makeCached(component: object, methodName: string, params?: object)
cached decorator getsimport { makeCached } from 'react-cached-callback';
class SomeComponent extends React.Component {
_onClick(index) {
return () => doSomething(index);
}
render() {
return (
<div>
{someArray.map((obj, index) => (
<ChildComponent onClick={this._onClick(index)} />
))}
</div>
);
}
}
makeCached(SomeComponent, '_onClick');
makeCached(SomeComponent, '_onClick', {index: 1});
// or
makeCached(SomeComponent, '_onClick', 1);
makeCached(SomeComponent, '_onClick', {getKey: (obj) => obj.id});
// or
makeCached(SomeComponent, '_onClick', (obj) => obj.id);
makeCached(SomeComponent, '_onClick', {pure: false);
The useGetCallback hook is similar to react's useCallback hook, but useGetCallback helps to create several callbacks in cycles.
import { useGetCallback } from 'react-cached-callback';
function SomeComponent ({someProp}) {
const getOnClick = useGetCallback(
(obj) => () => {
doSomething(obj, someProp);
},
(obj) => obj.id,
[someProp]
);
return (
<div>
{someArray.map((obj) => (
<ChildComponent onClick={getOnClick(obj)} />
))}
</div>
);
}
After 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.
You can pass the following parameters to useGetCallback:
getKey function gets all the same parameters as the function which creates callbacks.useCallback.useGetCallback returns a new callback for some key each time when one of dependencies or call parameters (callParams in the example below) are changed.
const getCallback = useGetCallback(
(...callParams) => {
return () => doSomething(...callParams)
},
dependencies
);
The 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.
The useEventCallback gets only one parameter - a callback.
const callback = useEventCallback(
(callParams) => { doSomething(...callParams) }
);
The 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.
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.
You can pass the following parameters to useGetEventCallback:
getKey function gets all the same parameters as the function which creates callbacks.const getOnClick = useGetEventCallback(
(obj) => {
return () => doSomething(obj)
},
(obj) => obj.id
);
FAQs
Library for excluding function generations on React's render function call
We found that react-cached-callback demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.