![Create React App Officially Deprecated Amid React 19 Compatibility Issues](https://cdn.sanity.io/images/cgdhsj6q/production/04fa08cf844d798abc0e1a6391c129363cc7e2ab-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Create React App Officially Deprecated Amid React 19 Compatibility Issues
Create React App is officially deprecated due to React 19 issues and lack of maintenance—developers should switch to Vite or other modern alternatives.
reversible-effect
Advanced tools
A collection of typed utility functions returning a callback to reverse their effect.
A zero dependency collection of typed utility functions returning a callback to reverse their effect.
This package includes reversible implementations of:
Hey you! Yes, you!
Are you tired of writing this?
useEffect(() => {
const myCallback = () => {
console.log('window resized');
};
window.addEventListener('resize', myCallback);
return () => {
window.removeEventListener('resize', myCallback);
};
}, []);
How about writing this instead?
useEffect(
() => addReversibleEventListener(window, 'resize', () => {
console.log('window resized');
}), []
);
using npm:
npm install reversible-effect
using yarn:
yarn add reversible-effect
Just import the required function from the package, here's an example for addReversibleEventListener
:
import { addReversibleEventListener } from 'reversible-effect';
See below for available functions and how to use them.
For a detailed explanation, check out this Medium article, but here's the gist of it:
Functions like setTimeout
or addEventListener
come with an accompanying function to reverse their effect, like clearTimeout
or removeEventListener
.
To be able to use them, you need to keep track of which effect you're trying to reverse, so you can call the appropriate function. To make matters worse, these functions require different parameters.
You also need to keep track of all references to identify what it is you want to cancel (a timeoutId
for clearTimeOut
or the eventName
as well as the callback
for removeEventListener
).
This package and the functions it provides aim to improve this:
Every function in this package returns a callback, which serves as its cleanup.
This allows you to do this:
// create an interval
const cancelInterval = setReversibleInterval(() => console.log('called'), 1000);
// cancel it
cancelInterval();
Note that you don't have to keep track of a timeoutID
, you can pass around a reference to the cleanup function to wherever you need it.
You can then call it without needing to know that it is an interval you're cancelling.
It would work just the same for an event:
// add an event listener
const remove = addReversibleEventListener(window, 'click', () => console.log('clicked'));
// remove it
remove();
useEffect
A common use case of these functions is within a react's useEffect
hook, which conveniently expects you to return function to reverse the effect.
As every function returns its own cleanup, you can return the reversible function from the hook directly.
This example will add the event listener, whenever the component mounts and remove it, when it unmounts:
useEffect(() => addReversibleEventListener(window, 'click', e => console.log(e.clientX, e.clientY)), []);
Here we start an interval, when the component mounts and stop it, when it unmounts:
useEffect(() => setReversibleInterval(() => setCount(count => count + 1), 500), []);
Note: If you add dependencies to the useEffect
hook here, the timer will reset any time a dependency changes.
See here to learn why and how to get around this.
If you have multiple effects, you could either define multiple useEffect
hooks or use them like this:
useEffect(() => {
const cancelTimeout = setReversibleTimeout(() => {}, 1000);
const removeEventListener = addEventListener(window, 'click', () => {});
return () => {
cancelTimeout();
removeEventListener();
};
}, []);
addReversibleEventListener
Reversible version of object.addEventListener
. → docs for original
This function has two overloads, which switch based on the provided target
. If target
is an object we know the supported event types for, typescript will both limit type
to supported types and provide the correct event type to the callback
.
function addReversibleEventListener(
target: EventTargetWithKnownEvents,
type: AvailableEventsForThisTarget, // string literal of available event listeners
listener: (e: SpecificEvent) => void, // Callback with Specific Event based on type
options?: boolean | AddEventListenerOptions
): () => void;
If we can't determine the event type, it will fall back to a generic version:
function addReversibleEventListener(
target: GenericTarget,
type: string,
listener: (e: Event) => void,
options?: boolean | AddEventListenerOptions
): () => void;
Note that there is shared behaviour with addEventListener
/removeEventListener
when called with the same arguments:
See below examples for details:
const callback = () => console.log('hello');
const cancel1 = addReversibleEventListener('click', callback);
cancel1();
const cancel2 = addReversibleEventListener('click', callback);
const cancel3 = addReversibleEventListener('click', callback);
// ⬆ Since the passed arguments are the same, the callback will only be called once, when the event is fired.
cancel1();
// ⬆ Even though it has been used before this will remove the listener. It is functionally equivalent to `cancel2` and `cancel3`.
If you specifically want to add a listener multiple times or make sure a cleanup function only concerns the listener it created, the solution is the same as with the originals – make the callback is referentially unique:
const cancel1 = addReversibleEventListener('click', e => callback(e));
const cancel2 = addReversibleEventListener('click', e => callback(e));
// ⬆ The passed parameter is referentially unique, so the callback is executed twice, when the event is fired.
cancel1();
// ⬆ This will only ever remove the first listener, the second still fires, until `cancel2()` is called.
setReversibleTimeout
Reversible version of [window.]setTimeout
. → docs for original
function setReversibleTimeout(
callback: (...args: any[]) => void, // function to be executed after `delay`
delay?: number = 0, // delay for timeout
...args: any[] // optional args to be passed into `callback`
): () => void;
setReversibleInterval
Reversible version of [window.]setInterval
. → docs for original
function setReversibleInterval(
callback: (...args: any[]) => void, // function to be executed every `delay`
delay?: number = 0, // delay between executions
...args: any[] // optional args to be passed into `callback`
): () => void;
requestReversibleAnimationFrame
Reversible version of window.requestAnimationFrame
. → docs for original
function requestReversibleAnimationFrame(
callback: (time: DOMHighResTimeStamp): void; // function to be executed on next repaint
): () => void;
Improvements or additions are most welcome!
Current list of planned support:
This package uses npm
as its package manager.
Fork / Clone the repo, run npm install
, then npm start
to build in watch mode.
Run npm run test:watch
to run the tests, don't forget to add new tests, if you add functionality.
Create a PR, describing your change.
Found a bug or need help? Add a new issue.
FAQs
A collection of typed utility functions returning a callback to reverse their effect.
The npm package reversible-effect receives a total of 6 weekly downloads. As such, reversible-effect popularity was classified as not popular.
We found that reversible-effect demonstrated a healthy version release cadence and project activity because the last version was released less than 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
Create React App is officially deprecated due to React 19 issues and lack of maintenance—developers should switch to Vite or other modern alternatives.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.