From 818677d3ee0876ab6da2870fbacbe3e47a7ba655 Mon Sep 17 00:00:00 2001 From: Tomasz Szatkowski Date: Tue, 19 Mar 2024 08:10:50 +0100 Subject: [PATCH 1/4] react 18 changes - getting registerStateContainer from context --- package-lock.json | 13 +++--- package.json | 4 +- src/ContainerRoot/ContainerRoot.tsx | 63 +++++++++++++++++------------ src/ContainerRoot/context.ts | 2 + src/ContainerRoot/re-register.ts | 16 -------- src/use-get-context.ts | 41 +++++++++++++++++++ src/use-selector.ts | 33 ++++++++++++--- 7 files changed, 118 insertions(+), 54 deletions(-) delete mode 100644 src/ContainerRoot/re-register.ts create mode 100644 src/use-get-context.ts diff --git a/package-lock.json b/package-lock.json index dfcbe48..045cc46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "key-value-state-container-react", - "version": "1.0.0", + "version": "1.0.20240316-1300", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "key-value-state-container-react", - "version": "1.0.0", + "version": "1.0.20240316-1300", "license": "MIT", "dependencies": { - "key-value-state-container": "^1.0.0", + "key-value-state-container": "file:~/key-value-state-container-1.0.20240316-1245.tgz", "lodash": "^4.17.4", "react": "^18.2.0" }, @@ -6320,7 +6320,9 @@ } }, "node_modules/key-value-state-container": { - "version": "1.0.2", + "version": "1.0.20240316-1245", + "resolved": "file:../../../../key-value-state-container-1.0.20240316-1245.tgz", + "integrity": "sha512-ZYWKIGlrH9g5Ai+MlksDZzmdI/5Chl7j0SXkTY0vNjDP8h4gxSsNGA5juS3e3dKK2MhQ2Nj/VxU7PidkQG0xNg==", "license": "MIT", "dependencies": { "lodash": "^4.17.4" @@ -11714,7 +11716,8 @@ "dev": true }, "key-value-state-container": { - "version": "1.0.2", + "version": "file:~/key-value-state-container-1.0.20240316-1245.tgz", + "integrity": "sha512-ZYWKIGlrH9g5Ai+MlksDZzmdI/5Chl7j0SXkTY0vNjDP8h4gxSsNGA5juS3e3dKK2MhQ2Nj/VxU7PidkQG0xNg==", "requires": { "lodash": "^4.17.4" } diff --git a/package.json b/package.json index 2e4c085..8a5d9b6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "key-value-state-container-react", - "version": "1.0.0", + "version": "1.0.20240316-1430", "date": "2023-Dec-10 10:10", "description": "React bindings for key-value-state-container", "main": "dist/index.js", @@ -33,7 +33,7 @@ }, "homepage": "https://github.com/WealthArc/key-value-state-container#readme", "dependencies": { - "key-value-state-container": "^1.0.0", + "key-value-state-container": "file:~/key-value-state-container-1.0.20240316-1245.tgz", "lodash": "^4.17.4", "react": "^18.2.0" }, diff --git a/src/ContainerRoot/ContainerRoot.tsx b/src/ContainerRoot/ContainerRoot.tsx index c6ccb57..86b7d54 100644 --- a/src/ContainerRoot/ContainerRoot.tsx +++ b/src/ContainerRoot/ContainerRoot.tsx @@ -26,13 +26,12 @@ import React, { PropsWithChildren, useEffect, useRef, useState } from "react"; import { Action, getUniqueId, - registerStateContainer, + registerStateContainer as libRegisterStateContainer, unregisterStateContainer, } from "key-value-state-container"; import { ContainerRootContext } from "./context"; import { ContainerRootProps } from "./props"; -import { reRegister } from "./re-register"; export const ContainerRoot = ( props: PropsWithChildren> @@ -48,10 +47,9 @@ export const ContainerRoot = ( persistence, reducer, } = props; - const runningFirstTimeRef = useRef(true); - if (runningFirstTimeRef.current) { - runningFirstTimeRef.current = false; - registerStateContainer({ + + const registerStateContainer = () => { + libRegisterStateContainer({ autoActions, autoState, config, @@ -60,29 +58,43 @@ export const ContainerRoot = ( persistence, reducer, }); - } + }; - useEffect(() => { + const runningFirstTimeRef = useRef(true); + if (runningFirstTimeRef.current) { + runningFirstTimeRef.current = false; /** - * Checking for unregistered container - * Container might be unregistered due to `useEffect` return function - * called twice in React 18 Strict Mode + * We need to register the container here, with the first render. + * + * Assuming the `console.log()` invocations are printed out for + * mount/unmount component lifecycle events (by `useEffect()`), + * the printout for React 18 Strict Mode would look as follows: + * + * useSelector mounted ⭐️ + * ContainerRoot mounted ⭐️⭐️ + * useSelector unmounted + * ContainerRoot unmounted + * useSelector mounted ⭐️⭐️⭐️ + * ContainerRoot mounted + * + * Please note is is way too late to register the container in the ⭐️⭐️ + * (as there was a `useSelector` call in ⭐️, that wanted to register + * callback listeners with an unregistered container!) + * + * The same story goes with `useSelector`, marked by ⭐️⭐️⭐️, + * that needs a container to be registered. + * + * Keep in mind the biggest possible memory issues for a container + * are the callback listeners mentioned above, + * as these can easily allocate GBs of memory + * (btw. this problem is handled by the `useSelector` code) */ - if (reRegister({ containerId })) { - registerStateContainer({ - autoActions, - autoState, - config, - containerId, - initialState, - persistence, - reducer, - }); - } + registerStateContainer(); + } + + useEffect(() => { return () => { - unregisterStateContainer({ - containerId, - }); + unregisterStateContainer({ containerId }); }; }, []); @@ -90,6 +102,7 @@ export const ContainerRoot = ( {children} diff --git a/src/ContainerRoot/context.ts b/src/ContainerRoot/context.ts index 641bdd8..ca0385b 100644 --- a/src/ContainerRoot/context.ts +++ b/src/ContainerRoot/context.ts @@ -27,10 +27,12 @@ import { getUniqueId } from "key-value-state-container"; export interface ContainerRootContextProps { containerId: string; + registerStateContainer: () => void; } export const ContainerRootContext = React.createContext< ContainerRootContextProps >({ containerId: getUniqueId(), + registerStateContainer: () => { }, }); diff --git a/src/ContainerRoot/re-register.ts b/src/ContainerRoot/re-register.ts deleted file mode 100644 index 52aca4b..0000000 --- a/src/ContainerRoot/re-register.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { - containerRegistered, -} from "key-value-state-container"; -import React from "react"; -import { RendersWithContainerId } from "../types/contracts"; - -/** - * For React versions 18 and above, the state-container might be unregistered - * due to wrapping with component and invoking component unmount! - */ -export const reRegister = ({ containerId }: RendersWithContainerId) => { - return ( - Number(React.version.split(".")[0]) >= 18 && - !containerRegistered({ containerId }) - ); -}; diff --git a/src/use-get-context.ts b/src/use-get-context.ts new file mode 100644 index 0000000..ee3e069 --- /dev/null +++ b/src/use-get-context.ts @@ -0,0 +1,41 @@ +/** + The MIT License (MIT) + + Copyright Tomasz Szatkowski and WealthArc https://www.wealtharc.com (c) 2023 + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +import { useContext } from "react"; + +import { + ContainerRootContext, + ContainerRootContextProps, +} from "./ContainerRoot/context"; + +type Result = { + containerIdFromContext: string; + registerStateContainer: () => void; +} + +export const useGetContext = (): Result => { + const { containerId, registerStateContainer } = + useContext(ContainerRootContext); + return { containerIdFromContext: containerId, registerStateContainer }; +}; diff --git a/src/use-selector.ts b/src/use-selector.ts index 9d8120e..94ad07d 100644 --- a/src/use-selector.ts +++ b/src/use-selector.ts @@ -2,14 +2,15 @@ import { useEffect, useRef, useState } from "react"; import { Action, ClientNotificationCallbackArgs, + containerRegistered, getContainer, getUniqueId, registerStateChangedCallback, TKnownStatePath, unregisterStateChangedCallback, } from "key-value-state-container"; -import { useGetContainerId } from "./use-get-container-id"; import { RendersWithContainerId } from "./types/contracts"; +import { useGetContext } from "./use-get-context"; interface Args extends Partial { @@ -67,8 +68,8 @@ export const useSelector = < `${listenerTag ? `${listenerTag}:` : ""}${getUniqueId()}` ); const unmountedRef = useRef(false); - const containerFromHook = useGetContainerId(); - const containerId = containerIdFromProps || containerFromHook; + const { containerIdFromContext, registerStateContainer } = useGetContext(); + const containerId = containerIdFromProps || containerIdFromContext; const initialState = getContainer({ containerId, @@ -78,15 +79,24 @@ export const useSelector = < const lateInvoke = typeof lateInvokeFromProps === "boolean" ? lateInvokeFromProps : true; const [currentState, setCurrentState] = useState(initialState); + useEffect(() => { - return () => { - unmountedRef.current = true; - }; + /** + * Component gets mounted + */ + unmountedRef.current = false; }, []); + useEffect(() => { if (switchOff) { return; } + /** + * Awkward, but necessary logic, explained in ContextRoot.tsx component. + */ + if (!containerRegistered({ containerId })) { + registerStateContainer(); + } const statePaths = typeof statePath === "string" ? [statePath] @@ -138,5 +148,16 @@ export const useSelector = < }; }, [setCurrentState]); + useEffect(() => { + console.log("useSelector mounted"); + return () => { + console.log("useSelector unmounted"); + /** + * component gets unmounted + */ + unmountedRef.current = true; + }; + }, []); + return currentState; }; From 24f8bd6c9538f845b597347b1854c2f2f4cfab88 Mon Sep 17 00:00:00 2001 From: Tomasz Szatkowski Date: Sun, 24 Mar 2024 16:53:06 +0100 Subject: [PATCH 2/4] Remove console.log statements in useSelector --- src/use-selector.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/use-selector.ts b/src/use-selector.ts index 94ad07d..7f50ebb 100644 --- a/src/use-selector.ts +++ b/src/use-selector.ts @@ -149,9 +149,7 @@ export const useSelector = < }, [setCurrentState]); useEffect(() => { - console.log("useSelector mounted"); return () => { - console.log("useSelector unmounted"); /** * component gets unmounted */ From 8bee98ac89d7910d9fdf09d89a24b1235f9dae3e Mon Sep 17 00:00:00 2001 From: Tomasz Szatkowski Date: Sun, 24 Mar 2024 18:01:48 +0100 Subject: [PATCH 3/4] added enhanced selector test/demo and improving tests --- src/tests/GameManaComponent.tsx | 21 +++++ src/tests/SumComponent.tsx | 12 ++- src/tests/state-container/game-logic.ts | 63 +++++++++++++ ...=> increment-decrement-container-logic.ts} | 4 +- src/tests/use-game-mana-selector.test.tsx | 46 +++++++++ ...use-increment-decrement-selector.test.tsx} | 6 +- src/types/contracts/index.ts | 7 +- src/types/contracts/selector.ts | 31 +++++++ src/use-enhanced-selector.ts | 93 +++++++++++++++++++ 9 files changed, 275 insertions(+), 8 deletions(-) create mode 100644 src/tests/GameManaComponent.tsx create mode 100644 src/tests/state-container/game-logic.ts rename src/tests/state-container/{enhanced-logic.ts => increment-decrement-container-logic.ts} (95%) create mode 100644 src/tests/use-game-mana-selector.test.tsx rename src/tests/{use-selector.test.tsx => use-increment-decrement-selector.test.tsx} (89%) create mode 100644 src/types/contracts/selector.ts create mode 100644 src/use-enhanced-selector.ts diff --git a/src/tests/GameManaComponent.tsx b/src/tests/GameManaComponent.tsx new file mode 100644 index 0000000..17c943b --- /dev/null +++ b/src/tests/GameManaComponent.tsx @@ -0,0 +1,21 @@ +import React from "react"; +import { RendersWithContainerId } from "../types/contracts"; +import { State } from "./state-container/game-logic"; +import { useEnhancedSelector } from "../use-enhanced-selector"; + +interface Props extends RendersWithContainerId {} + +export const GameManaComponent = ({ containerId }: Props) => { + const renderedRef = React.useRef(0); + const mana = useEnhancedSelector({ + containerId, + selector: ({ header }) => header.mana, + })(); + renderedRef.current = renderedRef.current + 1; + return ( +
+
Mana: {mana}
+
Rendered: {renderedRef.current}
+
+ ); +}; diff --git a/src/tests/SumComponent.tsx b/src/tests/SumComponent.tsx index a9b391b..4af0fff 100644 --- a/src/tests/SumComponent.tsx +++ b/src/tests/SumComponent.tsx @@ -1,7 +1,10 @@ import React from "react"; import { useSelector } from "../use-selector"; import { RendersWithContainerId } from "../types/contracts"; -import { Action, State } from "./state-container/enhanced-logic"; +import { + Action, + State, +} from "./state-container/increment-decrement-container-logic"; export interface RendersWithListeningToPath { path: keyof State | "*"; @@ -16,5 +19,10 @@ export const SumComponent = ({ containerId, path }: Props) => { statePath: [path], }); renderedRef.current = renderedRef.current + 1; - return
The sum is: {sum}
; + return ( +
+
The sum is: {sum}
+
Rendered: {renderedRef.current}
+
+ ); }; diff --git a/src/tests/state-container/game-logic.ts b/src/tests/state-container/game-logic.ts new file mode 100644 index 0000000..00ab8c7 --- /dev/null +++ b/src/tests/state-container/game-logic.ts @@ -0,0 +1,63 @@ +/** + * The enhanced logic adds a special action `zero` that bypasses the reducer. + */ +import { dispatchAction, Reducer } from "key-value-state-container"; + +export type Action = { + name: "use-mana"; + payload: number; +}; + +/** + * Header as displayed on the screen + */ +type Header = { + /** + * Mana points. + */ + mana: number; + + /** + * The score of the user. + */ + score: number; +}; + +export type State = { + header: Header; +}; + +export const reducer: Reducer = async ({ state, action }) => { + switch (action.name) { + case "use-mana": { + return { + ...state, + header: { + ...state.header, + mana: state.header.mana - action.payload, + }, + }; + } + default: { + return state; + } + } +}; + +export const dispatchActions = ({ + containerId, + randomArray, +}: { + containerId: string; + randomArray: number[]; +}) => { + for (let i = 0; i < randomArray.length; i++) { + dispatchAction({ + action: { + name: "use-mana", + payload: randomArray[i], + }, + containerId, + }); + } +}; diff --git a/src/tests/state-container/enhanced-logic.ts b/src/tests/state-container/increment-decrement-container-logic.ts similarity index 95% rename from src/tests/state-container/enhanced-logic.ts rename to src/tests/state-container/increment-decrement-container-logic.ts index 6bc9e61..e040849 100644 --- a/src/tests/state-container/enhanced-logic.ts +++ b/src/tests/state-container/increment-decrement-container-logic.ts @@ -1,7 +1,4 @@ -/** - * The enhanced logic adds a special action `zero` that bypasses the reducer. - */ import { dispatchAction, Reducer } from "key-value-state-container"; export type Action = @@ -26,6 +23,7 @@ export type Action = export type State = { sum: number; + /** * How many times the `increment` action has been dispatched. */ diff --git a/src/tests/use-game-mana-selector.test.tsx b/src/tests/use-game-mana-selector.test.tsx new file mode 100644 index 0000000..d9dea6e --- /dev/null +++ b/src/tests/use-game-mana-selector.test.tsx @@ -0,0 +1,46 @@ +import _ from "lodash"; +import React from "react"; + +import { render, act } from "@testing-library/react"; +import { finishedProcessingQueue } from "key-value-state-container"; + +import { reducer, dispatchActions } from "./state-container/game-logic"; +import { ContainerRoot } from "../ContainerRoot"; +import { GameManaComponent } from "./GameManaComponent"; + +const containerId = "use-enhanced-selector-state-container"; +const initialMana = 1000; + +test("useGameManaSelector test", async () => { + /** + * Mana spent for fighting monsters 👾. + */ + const manaSpentRandomArray = Array.from({ length: 25 }, () => _.random(1, 8)); + const expectedManaLeft = manaSpentRandomArray.reduce( + (acc, el) => acc - el, + initialMana + ); + const { getByTestId, unmount } = render( + + + + ); + await act(async () => { + dispatchActions({ containerId, randomArray: manaSpentRandomArray }); + await finishedProcessingQueue({ containerId }); + }); + expect(getByTestId("mana").innerHTML).toEqual(`Mana: ${expectedManaLeft}`); + expect(getByTestId("rendered").innerHTML).toEqual("Rendered: 2"); + act(() => { + unmount(); + }); +}); diff --git a/src/tests/use-selector.test.tsx b/src/tests/use-increment-decrement-selector.test.tsx similarity index 89% rename from src/tests/use-selector.test.tsx rename to src/tests/use-increment-decrement-selector.test.tsx index 5530615..1e9c0fb 100644 --- a/src/tests/use-selector.test.tsx +++ b/src/tests/use-increment-decrement-selector.test.tsx @@ -4,7 +4,10 @@ import React from "react"; import { render, act } from "@testing-library/react"; import { finishedProcessingQueue } from "key-value-state-container"; -import { reducer, dispatchActions } from "./state-container/enhanced-logic"; +import { + reducer, + dispatchActions, +} from "./state-container/increment-decrement-container-logic"; import { RendersWithListeningToPath, SumComponent } from "./SumComponent"; import { ContainerRoot } from "../ContainerRoot"; @@ -27,6 +30,7 @@ const useSelectorTest = async ({ path }: RendersWithListeningToPath) => { await finishedProcessingQueue({ containerId }); }); expect(getByTestId("sum").innerHTML).toEqual(`The sum is: ${expectedSum}`); + expect(getByTestId("rendered").innerHTML).toEqual("Rendered: 2"); act(() => { unmount(); }); diff --git a/src/types/contracts/index.ts b/src/types/contracts/index.ts index 90c0599..28dedf1 100644 --- a/src/types/contracts/index.ts +++ b/src/types/contracts/index.ts @@ -1,4 +1,7 @@ + + +export * from "./renders-with-container-id"; +export * from "./selector"; export * from "./use-dispatch-action"; export * from "./use-get-container-id"; -export * from "./use-selector"; -export * from "./renders-with-container-id"; \ No newline at end of file +export * from "./use-selector"; \ No newline at end of file diff --git a/src/types/contracts/selector.ts b/src/types/contracts/selector.ts new file mode 100644 index 0000000..725e58d --- /dev/null +++ b/src/types/contracts/selector.ts @@ -0,0 +1,31 @@ +/** + The MIT License (MIT) + + Copyright Tomasz Szatkowski, Patryk Parcheta + WealthArc https://www.wealtharc.com (c) 2023, 2024 + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +/** + * Unfortunately, the returned type has to be manually declared. + */ +export type Selector = ( + state: TState +) => TResult; diff --git a/src/use-enhanced-selector.ts b/src/use-enhanced-selector.ts new file mode 100644 index 0000000..7743501 --- /dev/null +++ b/src/use-enhanced-selector.ts @@ -0,0 +1,93 @@ +/** + The MIT License (MIT) + + Copyright Tomasz Szatkowski, Patryk Parcheta + WealthArc https://www.wealtharc.com (c) 2023, 2024 + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +import { + getContainer, + getUniqueId, + registerStateChangedCallback, + unregisterStateChangedCallback, +} from "key-value-state-container"; +import { useCallback, useEffect, useRef, useState } from "react"; +import { Selector } from "types/contracts"; + +type Args = { + containerId: string; + selector: Selector; + lateInvoke?: boolean; +}; + +export const useEnhancedSelector = + ({ + selector, + containerId, + lateInvoke, + }: Args) => + (): TResult => { + const listenerIdRef = useRef(getUniqueId()); + + const memoizedSelector = useCallback(selector, []); + + const [selectedState, setSelectedState] = useState>(() => { + return memoizedSelector( + getContainer({ + containerId, + ignoreUnregistered: true, + }) + ); + }); + + useEffect(() => { + const listenerId = listenerIdRef.current; + const lateInvokeValue = + typeof lateInvoke === "undefined" ? true : lateInvoke; + + registerStateChangedCallback({ + callback: ({ newState }) => { + const newSelectValue = memoizedSelector(newState); + + if ( + JSON.stringify(selectedState) !== JSON.stringify(newSelectValue) + ) { + setSelectedState(newSelectValue); + } + }, + listenerId, + containerId, + lateInvoke: lateInvokeValue, + statePath: "*", + }); + + return () => { + unregisterStateChangedCallback({ + containerId, + lateInvoke: lateInvokeValue, + listenerId, + statePath: "*", + }); + }; + }, [memoizedSelector, selectedState]); + + return selectedState; + }; From da0addffa0736e27f3a296459ee89d5bf1dc70da Mon Sep 17 00:00:00 2001 From: Tomasz Szatkowski Date: Sun, 24 Mar 2024 18:14:21 +0100 Subject: [PATCH 4/4] Update package.json version and key-value-state-container dependency --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 8a5d9b6..180bc22 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "key-value-state-container-react", - "version": "1.0.20240316-1430", + "version": "1.0.0", "date": "2023-Dec-10 10:10", "description": "React bindings for key-value-state-container", "main": "dist/index.js", @@ -33,7 +33,7 @@ }, "homepage": "https://github.com/WealthArc/key-value-state-container#readme", "dependencies": { - "key-value-state-container": "file:~/key-value-state-container-1.0.20240316-1245.tgz", + "key-value-state-container": "~1.0.0", "lodash": "^4.17.4", "react": "^18.2.0" },