Skip to content

Instantly share code, notes, and snippets.

@bekliev
Last active December 10, 2020 20:00
Show Gist options
  • Save bekliev/896709f1fffcde65a8dd55845e492ffa to your computer and use it in GitHub Desktop.
Save bekliev/896709f1fffcde65a8dd55845e492ffa to your computer and use it in GitHub Desktop.
Enhanced React useCallback hook with cleanup ability/feature (created in process of the issue: https://github.com/facebook/react/issues/15176#issuecomment-564029580)
import React from 'react';
/**
* memoized callback (a.k.a. useCallback) with cleanup ability/feature
*
* @param {Function} baseCallback callback that returns array with [callback, cleanup]
*
* callback - which will be passed to React.useCallback
*
* cleanup - which will be called in React.useEffect's cleanup function
*
* @param {Array} deps standard hook dependencies
*
* @return {Function} memoized callback by React.useCallback
*
* @example
* const callback = useCallbackCleanup(() => {
* let stop;
* return [
* function self(counter) => {
* // here goes your code
*
* if (someCondition) {
* setTimeout(() => !stop && self(counter + 1), 10 * 1000);
* return 'delayed';
* }
*
* // and return whatever you have to (bool, string, array, etc.)
* return true;
* },
* function cleanup() {
* stop = true;
* },
* ]
* }, [a, b, c])
*
* @example
* const callbackRef = useCallbackCleanup(() => {
* let node;
* const listner = (e) => {};
*
* return [
* (theNode) => {
* node = theNode;
* node.addEventListener('event', listner);
* },
* () => node.removeEventListener('event', listner)
* ]
* }, [a, b, c])
*
* return <div ref={callbackRef}>Some Text</div>
*/
export default function useCallbackCleanup(baseCallback, deps) {
const [callback, cleanup] = baseCallback();
if (typeof cleanup === 'function') {
React.useEffect(() => cleanup, deps);
}
return React.useCallback(callback, deps);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment