@diginet/use-reactive
Version:
A reactive state management hook for React.
61 lines • 2.77 kB
JavaScript
import React, { createContext, useContext, useRef } from "react";
import { useReactive } from "./useReactive"; // Assuming your existing function
/**
* Creates a globally shared reactive state using React Context and useReactive.
*
* @param initialState The initial state object
* @returns {ReactiveStoreProvider, useReactiveStore} Context provider and hook
*/
export function createReactiveStore(initialState, options) {
// Create the context and provider
const ReactiveStoreContext = createContext(null);
const ReactiveStoreProvider = ({ children }) => {
// Create the reactive state
const [state, subscribe, history] = useReactive(initialState, { ...options, noUseState: true });
// Return the provider
return (React.createElement(ReactiveStoreContext.Provider, { value: [state, subscribe, history] }, children));
};
/**
* Hook to access the reactive state and subscribe to changes.
*
* @returns {ReactiveStoreContext<T>} The reactive state and subscribe function
*/
const useReactiveStore = () => {
const context = useContext(ReactiveStoreContext);
if (!context) {
throw new Error("useReactiveStore must be used within a ReactiveStoreProvider");
}
const [, setTrigger] = React.useState(0);
// Create a proxy to track the subscriptions
const proxyProxy = useReactive(context[0], { noUseState: true });
// Track the subscriptions
const subscriptionsRef = useRef(null);
if (!subscriptionsRef.current) {
subscriptionsRef.current = new WeakMap();
}
const removerRef = useRef(null);
if (!removerRef.current) {
// Subscribe to the proxy to track the subscriptions
removerRef.current = proxyProxy[1](() => proxyProxy[0], function (state, key, _value, _previous, read) {
// Get the map of subscriptions for the state
let map = subscriptionsRef.current.get(state);
if (!map) {
// Create a new map if it doesn't exist
map = new Map();
subscriptionsRef.current.set(state, map);
}
// Check if the key is not already subscribed
if (read && !map.has(key)) {
// Subscribe to the key
map.set(key, true);
context[1](() => state[key], () => {
setTrigger((prev) => prev + 1);
});
}
}, 'deep', true);
}
return [proxyProxy[0], context[1], context[2]];
};
return [ReactiveStoreProvider, useReactiveStore];
}
//# sourceMappingURL=useReactiveStore.js.map