Skip to content

Instantly share code, notes, and snippets.

@hipdev
Created November 29, 2024 13:28
Show Gist options
  • Save hipdev/e0c2c3cdd1ca5d76cfb2ccfa00089cb1 to your computer and use it in GitHub Desktop.
Save hipdev/e0c2c3cdd1ca5d76cfb2ccfa00089cb1 to your computer and use it in GitHub Desktop.
LFades state implementation.
import { useEffect, useRef, useState } from "react";
let atomCount = 0;
export function atom(initialValue) {
let value = initialValue;
let subs = [];
let id = `atom${atomCount++}`;
return Object.freeze({
id,
get() {
return value;
},
set(newValue) {
if (value === newValue)
return;
value = newValue;
subs.forEach((cb) => {
cb(value);
});
},
sub(cb) {
subs.push(cb);
return () => {
subs = subs.filter((sub) => sub !== cb);
};
},
});
}
export function useAtom(atom) {
const [_count, rerender] = useState(0);
useSubscribe(atom, () => rerender((c) => c + 1));
return [atom.get(), atom.set];
}
export function useSubscribe(atom, cb, deps = []) {
useEffect(() => atom.sub(cb), [atom, ...deps]);
}
var HydrateState;
(function (HydrateState) {
HydrateState[HydrateState["Pending"] = 0] = "Pending";
HydrateState[HydrateState["Done"] = 1] = "Done";
HydrateState[HydrateState["Effect"] = 2] = "Effect";
})(HydrateState || (HydrateState = {}));
export function useHydrate(cb, deps) {
const hydratedRef = useRef(HydrateState.Pending);
// Hydrate immediately for SSR and for the first render in the browser, this
// should avoid hydration mismatches.
if (hydratedRef.current === HydrateState.Pending) {
hydratedRef.current = HydrateState.Done;
cb();
}
// This allows bundlers to remove the effect at build time.
if (typeof window !== "undefined") {
useEffect(() => {
// Prevent a double hydration and potential mismatch issues by running the
// callback only from the second render onwards.
if (hydratedRef.current === HydrateState.Done) {
hydratedRef.current = HydrateState.Effect;
}
else {
cb();
}
}, deps);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment