From 1b721233f6fa11aa5eae771c3d4164f6c98dd54e Mon Sep 17 00:00:00 2001 From: "Sergey S. Volkov" Date: Sat, 16 May 2020 13:07:35 +0300 Subject: [PATCH] [new package] @reffect/strict (#8) * feat: add the "strict" package; fix(@reffect/react): problems with unmounted react hooks * bump: @reffect/react to 1.1.3 * docs: update README for strict * chore: set initial version for strict package --- packages/react/.size-limit.json | 6 ++-- packages/react/CHANGELOG.md | 6 ++++ packages/react/package.json | 2 +- packages/react/src/useEffectState.ts | 9 +++++- packages/react/src/useStore.ts | 9 +++++- packages/strict/.gitignore | 4 +++ packages/strict/.size-limit.json | 17 ++++++++++ packages/strict/CHANGELOG.md | 3 ++ packages/strict/README.md | 29 +++++++++++++++++ packages/strict/package.json | 48 ++++++++++++++++++++++++++++ packages/strict/src/index.ts | 29 +++++++++++++++++ 11 files changed, 156 insertions(+), 6 deletions(-) create mode 100644 packages/strict/.gitignore create mode 100644 packages/strict/.size-limit.json create mode 100644 packages/strict/CHANGELOG.md create mode 100644 packages/strict/README.md create mode 100644 packages/strict/package.json create mode 100644 packages/strict/src/index.ts diff --git a/packages/react/.size-limit.json b/packages/react/.size-limit.json index ff9958f..2df3c2a 100644 --- a/packages/react/.size-limit.json +++ b/packages/react/.size-limit.json @@ -2,16 +2,16 @@ { "path": "reffect-react.es.js", "webpack": false, - "limit": "300 B" + "limit": "335 B" }, { "path": "reffect-react.cjs.js", "webpack": false, - "limit": "350 B" + "limit": "355 B" }, { "path": "reffect-react.umd.js", "webpack": false, - "limit": "450 B" + "limit": "455 B" } ] diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index 9abff81..c786986 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,3 +1,9 @@ +# 1.1.3 + +### Fix: + +1. update hooks states only if hook is mounted + # 1.1.2 ### Minor: diff --git a/packages/react/package.json b/packages/react/package.json index de0b912..41d1808 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@reffect/react", - "version": "1.1.2", + "version": "1.1.3", "description": "React bindings for Reffect", "scripts": { "build": "node ../../build/build.js", diff --git a/packages/react/src/useEffectState.ts b/packages/react/src/useEffectState.ts index 0288c06..0b77177 100644 --- a/packages/react/src/useEffectState.ts +++ b/packages/react/src/useEffectState.ts @@ -5,7 +5,14 @@ import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect"; export const useEffectState = (effect: Effect) => { const [state, setState] = useState(null); - useIsomorphicLayoutEffect(() => manage(effect).subscribe(state => setState(state)), []); + useIsomorphicLayoutEffect(() => { + let isMount = true; + const unsubscribe = manage(effect).subscribe(state => isMount && setState(state)); + return () => { + isMount = false; + unsubscribe(); + }; + }, []); return { pending: state === "pending", diff --git a/packages/react/src/useStore.ts b/packages/react/src/useStore.ts index 49260b4..e7f38c2 100644 --- a/packages/react/src/useStore.ts +++ b/packages/react/src/useStore.ts @@ -7,7 +7,14 @@ const reducer = (state: any, newState: any) => ({ ...newState }); export const useStore = (store: Store): Store => { const [state, setState] = useReducer(reducer, store); - useIsomorphicLayoutEffect(() => manage(store).subscribe(() => setState(store)), []); + useIsomorphicLayoutEffect(() => { + let isMount = true; + const unsubscribe = manage(store).subscribe(() => isMount && setState(store)); + return () => { + isMount = false; + unsubscribe(); + }; + }, []); return state; }; diff --git a/packages/strict/.gitignore b/packages/strict/.gitignore new file mode 100644 index 0000000..49baf40 --- /dev/null +++ b/packages/strict/.gitignore @@ -0,0 +1,4 @@ +reffect-strict.*.js +reffect-strict.d.ts +reffect-strict.*.js.map +package-lock.json \ No newline at end of file diff --git a/packages/strict/.size-limit.json b/packages/strict/.size-limit.json new file mode 100644 index 0000000..c6d481d --- /dev/null +++ b/packages/strict/.size-limit.json @@ -0,0 +1,17 @@ +[ + { + "path": "reffect-strict.es.js", + "webpack": false, + "limit": "310 B" + }, + { + "path": "reffect-strict.cjs.js", + "webpack": false, + "limit": "340 B" + }, + { + "path": "reffect-strict.umd.js", + "webpack": false, + "limit": "450 B" + } +] diff --git a/packages/strict/CHANGELOG.md b/packages/strict/CHANGELOG.md new file mode 100644 index 0000000..323047f --- /dev/null +++ b/packages/strict/CHANGELOG.md @@ -0,0 +1,3 @@ +# 0.0.1 + +Created project diff --git a/packages/strict/README.md b/packages/strict/README.md new file mode 100644 index 0000000..409e736 --- /dev/null +++ b/packages/strict/README.md @@ -0,0 +1,29 @@ +
+ +[![reffect logo](https://raw.githubusercontent.com/acacode/reffect/master/assets/reffect.png)](https://github.com/acacode/reffect) +[![npm](https://img.shields.io/npm/v/@reffect/logger?style=flat-square&color=blue)](https://www.npmjs.com/package/@reffect/logger) +[![npm bundle size](https://img.shields.io/bundlephobia/minzip/@reffect/logger?style=flat-square&color=blue)](https://bundlephobia.com/result?p=@reffect/logger) +[![license](https://img.shields.io/github/license/acacode/reffect?style=flat-square&color=blue)](https://github.com/acacode/reffect) + +
+ +Reffect — is a declarative and reactive multi-store state manager for JavaScript/TypeScript applications inspired by [Reatom](https://github.com/artalar/reatom) and [Effector](https://github.com/zerobias/effector) + +# @reffect/strict + +Store middleware for [`Reffect`](https://github.com/acacode/reffect) + +## How to use + +```ts +import { store, effect } from "@reffect/core"; +import { strictUpdate } from "@reffect/logger"; + +const projectsStore = store({ projects: [] }, "projects", [strictUpdate]); + +const setProjects = effect(projectsStore, "projects"); +// ... + +setProjects(["foo", "bar"]); // state of projectsStore will update to { projects: ["foo", "bar"] } +setProjects(["foo", "bar"]); // state of projectsStore won't update because new state and current are equals +``` diff --git a/packages/strict/package.json b/packages/strict/package.json new file mode 100644 index 0000000..fbd729c --- /dev/null +++ b/packages/strict/package.json @@ -0,0 +1,48 @@ +{ + "name": "@reffect/strict", + "version": "0.0.1", + "description": "strict update store middleware for Reffect", + "scripts": { + "build": "node ../../build/build.js", + "size": "size-limit" + }, + "author": "acacode", + "license": "MIT", + "readme": "README.md", + "private": false, + "sideEffects": false, + "main": "reffect-strict.cjs.js", + "typings": "reffect-strict.d.ts", + "umd:main": "reffect-strict.umd.js", + "jsnext:main": "reffect-strict.es.js", + "module": "reffect-strict.es.js", + "peerDependencies": { "@reffect/core": "^1.5.0" }, + "devDependencies": { + "@reffect/core": "^1.5.0", + "@size-limit/preset-small-lib": "^4.2.1", + "size-limit": "^4.2.1" + }, + "files": [ + "LICENSE", + "reffect-strict.d.ts", + "reffect-strict.cjs.js", + "reffect-strict.cjs.js.map", + "reffect-strict.es.js", + "reffect-strict.es.js.map", + "reffect-strict.umd.js", + "reffect-strict.umd.js.map" + ], + "keywords": [ + "redux", + "effector", + "mobx", + "state", + "store", + "flux", + "reactive", + "state-manager", + "state manager", + "reffect" + ], + "gitHead": "a724ce9d6d802cf83fec609ad4664172a4694471" +} \ No newline at end of file diff --git a/packages/strict/src/index.ts b/packages/strict/src/index.ts new file mode 100644 index 0000000..eed9842 --- /dev/null +++ b/packages/strict/src/index.ts @@ -0,0 +1,29 @@ +import { StoreType, manage } from "@reffect/core"; + +const equals = (obj1: object, obj2: object): obj1 is typeof obj2 => { + if (obj1 === obj2) return true; + if (!(obj1 instanceof Object) || !(obj2 instanceof Object)) return false; + if (obj1.constructor !== obj2.constructor) return false; + + for (const property in obj1) { + if (obj1.hasOwnProperty(property) && (!obj2.hasOwnProperty(property) || !equals(obj1[property], obj2[property]))) + return false; + } + + for (const property in obj2) { + if (obj2.hasOwnProperty(property) && !obj1.hasOwnProperty(property)) return false; + } + return true; +}; + +export const strictUpdate = (store: Store, copy: (obj: object) => object) => { + const storeManager = manage(store); + const originalPartialUpdate = storeManager.partialUpdate; + + storeManager.partialUpdate = (storeUpdate: Partial) => + storeUpdate && + !equals(store, copy({ ...storeManager.state, ...storeUpdate })) && + originalPartialUpdate(storeUpdate); + + return store; +};