Skip to content

Instantly share code, notes, and snippets.

@SaiEashwarKS
Last active June 28, 2022 14:16
Show Gist options
  • Save SaiEashwarKS/26cb0753f9cae0799db6a4a3b24468fd to your computer and use it in GitHub Desktop.
Save SaiEashwarKS/26cb0753f9cae0799db6a4a3b24468fd to your computer and use it in GitHub Desktop.
import React, { useEffect, useState } from 'react';
import { batch } from 'react-redux';
import { mountIntoContainer, unmountFromContainer } from './SingletonHooksContainer';
export function singletonHook<HookReturn = any, HookArgs extends any[] = any[]>(
initValue: HookReturn,
useHookBody: () => HookReturn
) {
let mounted = false;
let initStateCalculated = false;
let lastKnownState: HookReturn | undefined;
let consumers: React.Dispatch<React.SetStateAction<HookReturn>>[] = [];
const applyStateChange = (newState: HookReturn) => {
lastKnownState = newState;
batch(() => consumers.forEach((setState) => setState(newState)));
};
const stateInitializer = () => {
if (!initStateCalculated) {
lastKnownState = initValue;
initStateCalculated = true;
}
return lastKnownState as HookReturn;
};
return (args: HookArgs) => {
const [state, setState] = useState(stateInitializer);
useEffect(() => {
if (!mounted) {
mounted = true;
mountIntoContainer<HookReturn, HookArgs>({ initValue, useHookBody, applyStateChange, args });
}
consumers.push(setState);
if (lastKnownState && lastKnownState !== state) {
setState(lastKnownState);
}
return () => {
consumers.splice(consumers.indexOf(setState), 1);
if (consumers.length === 0) {
mounted = false;
initStateCalculated = false;
lastKnownState = undefined;
unmountFromContainer({ initValue, useHookBody, applyStateChange, args });
}
};
}, []);
return state;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment