diff --git a/CHANGELOG.md b/CHANGELOG.md index c99760a..bc1fe4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Change Log +## v2.0.2 +* Updated for better intellisence using templates +* Added `useStore` to be attached to objects returned from `setupStore`, which wraps and abstracts the need to explicitly call `useContext(StoreContext)` when subscribing to a store. This also helps with mocking store objects when unit testing components subscribed to a store. + ## v2.0.1 * Minor dependency updates diff --git a/examples/counter-react/yarn.lock b/examples/counter-react/yarn.lock index a752590..4829812 100644 --- a/examples/counter-react/yarn.lock +++ b/examples/counter-react/yarn.lock @@ -1502,7 +1502,7 @@ integrity sha512-DetpxZw1fzPD5xUBrIAoplLChO2VB8DlL5Gg+I1IR9b2wPqYIca2WSUxL5g1vLeR4MsQq1NeWriXAVffV+U1Fw== "@shipt/osmosis@../../osmosis": - version "2.0.0" + version "2.0.2" "@sinonjs/commons@^1.7.0": version "1.8.2" diff --git a/osmosis/package.json b/osmosis/package.json index d0f6ce9..7131330 100644 --- a/osmosis/package.json +++ b/osmosis/package.json @@ -1,6 +1,6 @@ { "name": "@shipt/osmosis", - "version": "2.0.1", + "version": "2.0.2", "description": "A lightweight state management library for React and React Native", "keywords": [ "react", diff --git a/osmosis/src/setupStore.js b/osmosis/src/setupStore.js index 31216e0..10e726e 100644 --- a/osmosis/src/setupStore.js +++ b/osmosis/src/setupStore.js @@ -1,5 +1,5 @@ /* eslint-disable react/prop-types */ -import React, { createContext } from 'react'; +import React, { createContext, useContext } from 'react'; let _defaultConfig = { proxyEnabled: true, legacyReturnStoreAsArray: false }; @@ -20,20 +20,29 @@ export const configureSetupStore = config => { */ /** + * @template T + * @callback useStore + * @returns {T} + */ + +/** + * @template T * @typedef Store - * @type {Object} - * @property {Object} Context - The React Context for the store + * @property {React.Context} Context - The React Context for the store * @property {Object} Provider - The higher order component provider for the store + * @property {useStore} useStore - Returns result of useContext(Context) */ /** - * @param {useCustomHook} useCustomHook + * @template T + * @param {function(object) : T} useCustomHook * @param {SetupStoreConfig} [config = { proxyEnabled: false }] - The setup store config - * @returns {Store} + * @returns {T & Store} */ const setupStore = (useCustomHook, config = {}) => { config = { ..._defaultConfig, ...config }; const StoreContext = createContext(); + // If proxy is not supported let storeRef = {}; @@ -41,43 +50,14 @@ const setupStore = (useCustomHook, config = {}) => { let storeProxy; let storeProxyObject = { ref: {} }; - // Legacy Store Provider - const withLegacyStoreContext = WrappedComponent => props => { - let storeKey = props.storeKey; - let store = useCustomHook(props); - if (!!store.Context) throw new Error("'Context' property is protected and cannot exist on a store object"); - if (!!store.Provider) throw new Error("'Provider' property is protected and cannot exist on a store object"); - - if (storeProxy) { - if (storeKey) { - storeProxyObject.ref[storeKey] = store; - } else storeProxyObject.ref = store; - } else { - if (storeKey) { - storeRef[storeKey] = store; - } else { - for (let key in store) { - storeRef[key] = store[key]; - } - } - } - - const value = config.legacyReturnStoreAsArray ? [store] : store; - - return ( - - - - ); - }; - - // New Store Provider + // Store Provider const withStoreContext = WrappedComponent => { const StoreContextWrapper = ({ children, ...props }) => { let storeKey = props.storeKey; let store = useCustomHook(props); if (!!store.Context) throw new Error("'Context' property is protected and cannot exist on a store object"); if (!!store.Provider) throw new Error("'Provider' property is protected and cannot exist on a store object"); + if (!!store.useStore) throw new Error("'useStore' property is protected and cannot exist on a store object"); if (storeProxy) { if (storeKey) { @@ -106,12 +86,14 @@ const setupStore = (useCustomHook, config = {}) => { return Wrapper; }; + const useStore = () => useContext(StoreContext); + if (!!Proxy && config.proxyEnabled) { storeProxy = new Proxy(storeProxyObject, { get: (target, property) => { if (property === 'Context') return StoreContext; if (property === 'Provider') return withStoreContext; - if (property === 'LegacyProvider') return withLegacyStoreContext; + if (property === 'useStore') return target.ref[property] ?? useStore; return target.ref[property]; }, set: (target, property, value) => (target.ref[property] = value) @@ -119,7 +101,7 @@ const setupStore = (useCustomHook, config = {}) => { } else { storeRef.Context = StoreContext; storeRef.Provider = withStoreContext; - storeRef.LegacyProvider = withLegacyStoreContext; + storeRef.useStore = useStore; } return storeProxy || storeRef;