react-singleton-hook
Advanced tools
Comparing version 3.2.3 to 3.3.0
@@ -77,2 +77,5 @@ (function (global, factory) { | ||
mountQueue.push(item); | ||
return function () { | ||
throw new Error('Can not unmount container! It is like a bug in react-singleton-hook library, because of unmountIfNoConsumers: true'); // mountQueue = mountQueue.filter(i => i !== item); | ||
}; | ||
}; | ||
@@ -97,5 +100,12 @@ | ||
mountIntoContainer = function mountIntoContainer(item) { | ||
return setHooks(function (hooks) { | ||
setHooks(function (hooks) { | ||
return [].concat(hooks, [item]); | ||
}); | ||
return function () { | ||
setHooks(function (hooks) { | ||
return hooks.filter(function (i) { | ||
return i !== item; | ||
}); | ||
}); | ||
}; | ||
}; | ||
@@ -117,10 +127,18 @@ | ||
mountIntoContainer(hook); | ||
return mountIntoContainer(hook); | ||
}; | ||
var singletonHook = function singletonHook(initValue, useHookBody) { | ||
var singletonHook = function singletonHook(initValue, useHookBody, options) { | ||
if (options === void 0) { | ||
options = {}; | ||
} | ||
var mounted = false; | ||
var removeHook = undefined; | ||
var initStateCalculated = false; | ||
var lastKnownState = undefined; | ||
var consumers = []; | ||
var _options = options, | ||
_options$unmountIfNoC = _options.unmountIfNoConsumers, | ||
unmountIfNoConsumers = _options$unmountIfNoC === void 0 ? false : _options$unmountIfNoC; | ||
@@ -153,3 +171,3 @@ var applyStateChange = function applyStateChange(newState) { | ||
mounted = true; | ||
addHook({ | ||
removeHook = addHook({ | ||
initValue: initValue, | ||
@@ -169,2 +187,7 @@ useHookBody: useHookBody, | ||
consumers.splice(consumers.indexOf(setState), 1); | ||
if (consumers.length === 0 && unmountIfNoConsumers) { | ||
removeHook(); | ||
mounted = false; | ||
} | ||
}; // eslint-disable-next-line react-hooks/exhaustive-deps | ||
@@ -171,0 +194,0 @@ }, []); |
@@ -1,1 +0,1 @@ | ||
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("react"),require("react-dom")):"function"==typeof define&&define.amd?define(["exports","react","react-dom"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self).ReactSingletonHook={},e.React,e.ReactDOM)}(this,(function(e,n,t){"use strict";function o(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var r=o(n);function u(){return(u=Object.assign||function(e){for(var n=1;arguments.length>n;n++){var t=arguments[n];for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&(e[o]=t[o])}return e}).apply(this,arguments)}var a=function(e){var t=e.useHookBody,o=e.applyStateChange,r=n.useRef(e.initValue);if("function"!=typeof t)throw Error("function expected as hook body parameter. got "+typeof t);var u=t();return n.useLayoutEffect((function(){r.current!==u&&(r.current=u,o(u))}),[o,u]),null},i=function(e){console&&console.warn&&console.warn(e)},f="object"==typeof self&&self.self===self&&self||"object"==typeof global&&global.global===global&&global||this,l=!1,c=!1,s=!1,d=[],p=function(e){d.push(e)},y=function(){c=!0,n.useEffect((function(){l&&i("SingletonHooksContainer is mounted second time. You should mount SingletonHooksContainer before any other component and never unmount it.Alternatively, dont use SingletonHooksContainer it at all, we will handle that for you."),l=!0}),[]);var e=n.useState([]),t=e[0],o=e[1];return n.useEffect((function(){p=function(e){return o((function(n){return[].concat(n,[e])}))},o(d)}),[]),r.default.createElement(r.default.Fragment,null,t.map((function(e,n){return r.default.createElement(a,u({},e,{key:n}))})))},m=function(e){var n;c||s||(s=!0,n=y,f.document&&f.document.createElement?t.render(r.default.createElement(n,null),f.document.createElement("div")):i("Can not mount SingletonHooksContainer on server side. Did you manage to run useEffect on server? Please mount SingletonHooksContainer into your components tree manually.")),p(e)},g=function(e,o){var r=!1,u=!1,a=void 0,i=[],f=function(e){a=e,t.unstable_batchedUpdates((function(){return i.forEach((function(n){return n(e)}))}))},l=function(){return u||(a="function"==typeof e?e():e,u=!0),a};return function(){var t=n.useState(l),u=t[0],c=t[1];return n.useEffect((function(){return r||(r=!0,m({initValue:e,useHookBody:o,applyStateChange:f})),i.push(c),a!==u&&c(a),function(){i.splice(i.indexOf(c),1)}}),[]),u}},h={singletonHook:g,SingletonHooksContainer:y};e.SingletonHooksContainer=y,e.default=h,e.singletonHook=g,Object.defineProperty(e,"__esModule",{value:!0})})); | ||
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("react"),require("react-dom")):"function"==typeof define&&define.amd?define(["exports","react","react-dom"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self).ReactSingletonHook={},e.React,e.ReactDOM)}(this,(function(e,n,t){"use strict";function o(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var r=o(n);function u(){return(u=Object.assign||function(e){for(var n=1;arguments.length>n;n++){var t=arguments[n];for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&(e[o]=t[o])}return e}).apply(this,arguments)}var i=function(e){var t=e.useHookBody,o=e.applyStateChange,r=n.useRef(e.initValue);if("function"!=typeof t)throw Error("function expected as hook body parameter. got "+typeof t);var u=t();return n.useLayoutEffect((function(){r.current!==u&&(r.current=u,o(u))}),[o,u]),null},a=function(e){console&&console.warn&&console.warn(e)},f="object"==typeof self&&self.self===self&&self||"object"==typeof global&&global.global===global&&global||this,l=!1,c=!1,s=!1,d=[],p=function(e){return d.push(e),function(){throw Error("Can not unmount container! It is like a bug in react-singleton-hook library, because of unmountIfNoConsumers: true")}},m=function(){c=!0,n.useEffect((function(){l&&a("SingletonHooksContainer is mounted second time. You should mount SingletonHooksContainer before any other component and never unmount it.Alternatively, dont use SingletonHooksContainer it at all, we will handle that for you."),l=!0}),[]);var e=n.useState([]),t=e[0],o=e[1];return n.useEffect((function(){p=function(e){return o((function(n){return[].concat(n,[e])})),function(){o((function(n){return n.filter((function(n){return n!==e}))}))}},o(d)}),[]),r.default.createElement(r.default.Fragment,null,t.map((function(e,n){return r.default.createElement(i,u({},e,{key:n}))})))},y=function(e){var n;return c||s||(s=!0,n=m,f.document&&f.document.createElement?t.render(r.default.createElement(n,null),f.document.createElement("div")):a("Can not mount SingletonHooksContainer on server side. Did you manage to run useEffect on server? Please mount SingletonHooksContainer into your components tree manually.")),p(e)},g=function(e,o,r){void 0===r&&(r={});var u=!1,i=void 0,a=!1,f=void 0,l=[],c=r.unmountIfNoConsumers,s=void 0!==c&&c,d=function(e){f=e,t.unstable_batchedUpdates((function(){return l.forEach((function(n){return n(e)}))}))},p=function(){return a||(f="function"==typeof e?e():e,a=!0),f};return function(){var t=n.useState(p),r=t[0],a=t[1];return n.useEffect((function(){return u||(u=!0,i=y({initValue:e,useHookBody:o,applyStateChange:d})),l.push(a),f!==r&&a(f),function(){l.splice(l.indexOf(a),1),0===l.length&&s&&(i(),u=!1)}}),[]),r}},h={singletonHook:g,SingletonHooksContainer:m};e.SingletonHooksContainer=m,e.default=h,e.singletonHook=g,Object.defineProperty(e,"__esModule",{value:!0})})); |
@@ -14,2 +14,5 @@ function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } | ||
mountQueue.push(item); | ||
return function () { | ||
throw new Error('Can not unmount container! It is like a bug in react-singleton-hook library, because of unmountIfNoConsumers: true'); // mountQueue = mountQueue.filter(i => i !== item); | ||
}; | ||
}; | ||
@@ -34,5 +37,12 @@ | ||
mountIntoContainer = function mountIntoContainer(item) { | ||
return setHooks(function (hooks) { | ||
setHooks(function (hooks) { | ||
return [].concat(hooks, [item]); | ||
}); | ||
return function () { | ||
setHooks(function (hooks) { | ||
return hooks.filter(function (i) { | ||
return i !== item; | ||
}); | ||
}); | ||
}; | ||
}; | ||
@@ -54,3 +64,3 @@ | ||
mountIntoContainer(hook); | ||
return mountIntoContainer(hook); | ||
}; | ||
@@ -57,0 +67,0 @@ export var resetLocalStateForTests = function resetLocalStateForTests() { |
import { useEffect, useState } from 'react'; | ||
import { addHook } from './components/SingletonHooksContainer'; | ||
import { batch } from './utils/env'; | ||
export var singletonHook = function singletonHook(initValue, useHookBody) { | ||
export var singletonHook = function singletonHook(initValue, useHookBody, options) { | ||
if (options === void 0) { | ||
options = {}; | ||
} | ||
var mounted = false; | ||
var removeHook = undefined; | ||
var initStateCalculated = false; | ||
var lastKnownState = undefined; | ||
var consumers = []; | ||
var _options = options, | ||
_options$unmountIfNoC = _options.unmountIfNoConsumers, | ||
unmountIfNoConsumers = _options$unmountIfNoC === void 0 ? false : _options$unmountIfNoC; | ||
@@ -36,3 +44,3 @@ var applyStateChange = function applyStateChange(newState) { | ||
mounted = true; | ||
addHook({ | ||
removeHook = addHook({ | ||
initValue: initValue, | ||
@@ -52,2 +60,7 @@ useHookBody: useHookBody, | ||
consumers.splice(consumers.indexOf(setState), 1); | ||
if (consumers.length === 0 && unmountIfNoConsumers) { | ||
removeHook(); | ||
mounted = false; | ||
} | ||
}; // eslint-disable-next-line react-hooks/exhaustive-deps | ||
@@ -54,0 +67,0 @@ }, []); |
@@ -6,4 +6,11 @@ | ||
declare namespace ReactSingletonHook { | ||
function singletonHook<ValueType>(initialState: ValueType | (() => ValueType), useHook: () => ValueType): () => ValueType; | ||
function singletonHook<ValueType>( | ||
initialState: ValueType | (() => ValueType), | ||
useHook: () => ValueType, | ||
options?: { | ||
unmountIfNoConsumers?: boolean | ||
} | ||
): () => ValueType; | ||
function SingletonHooksContainer(): any; | ||
} |
@@ -27,2 +27,5 @@ "use strict"; | ||
mountQueue.push(item); | ||
return function () { | ||
throw new Error('Can not unmount container! It is like a bug in react-singleton-hook library, because of unmountIfNoConsumers: true'); // mountQueue = mountQueue.filter(i => i !== item); | ||
}; | ||
}; | ||
@@ -48,5 +51,12 @@ | ||
mountIntoContainer = function mountIntoContainer(item) { | ||
return setHooks(function (hooks) { | ||
setHooks(function (hooks) { | ||
return [].concat(hooks, [item]); | ||
}); | ||
return function () { | ||
setHooks(function (hooks) { | ||
return hooks.filter(function (i) { | ||
return i !== item; | ||
}); | ||
}); | ||
}; | ||
}; | ||
@@ -71,3 +81,3 @@ | ||
mountIntoContainer(hook); | ||
return mountIntoContainer(hook); | ||
}; | ||
@@ -74,0 +84,0 @@ |
@@ -12,7 +12,15 @@ "use strict"; | ||
var singletonHook = function singletonHook(initValue, useHookBody) { | ||
var singletonHook = function singletonHook(initValue, useHookBody, options) { | ||
if (options === void 0) { | ||
options = {}; | ||
} | ||
var mounted = false; | ||
var removeHook = undefined; | ||
var initStateCalculated = false; | ||
var lastKnownState = undefined; | ||
var consumers = []; | ||
var _options = options, | ||
_options$unmountIfNoC = _options.unmountIfNoConsumers, | ||
unmountIfNoConsumers = _options$unmountIfNoC === void 0 ? false : _options$unmountIfNoC; | ||
@@ -45,3 +53,3 @@ var applyStateChange = function applyStateChange(newState) { | ||
mounted = true; | ||
(0, _SingletonHooksContainer.addHook)({ | ||
removeHook = (0, _SingletonHooksContainer.addHook)({ | ||
initValue: initValue, | ||
@@ -61,2 +69,7 @@ useHookBody: useHookBody, | ||
consumers.splice(consumers.indexOf(setState), 1); | ||
if (consumers.length === 0 && unmountIfNoConsumers) { | ||
removeHook(); | ||
mounted = false; | ||
} | ||
}; // eslint-disable-next-line react-hooks/exhaustive-deps | ||
@@ -63,0 +76,0 @@ }, []); |
{ | ||
"name": "react-singleton-hook", | ||
"version": "3.2.3", | ||
"version": "3.3.0", | ||
"description": "Share custom hook state across all components", | ||
@@ -39,3 +39,3 @@ "keywords": [ | ||
"peerDependencies": { | ||
"react": "15 - 17" | ||
"react": "15 - 18" | ||
}, | ||
@@ -52,33 +52,36 @@ "peerDependenciesMeta": { | ||
"devDependencies": { | ||
"@babel/cli": "^7.16.0", | ||
"@babel/core": "^7.16.5", | ||
"@babel/eslint-parser": "^7.16.5", | ||
"@babel/plugin-proposal-object-rest-spread": "^7.16.5", | ||
"@babel/plugin-transform-react-display-name": "^7.16.5", | ||
"@babel/plugin-transform-react-jsx": "^7.16.5", | ||
"@babel/preset-env": "^7.16.5", | ||
"@rollup/plugin-commonjs": "^21.0.1", | ||
"@rollup/plugin-node-resolve": "^13.1.1", | ||
"@rollup/plugin-replace": "^3.0.0", | ||
"@testing-library/jest-dom": "^5.16.1", | ||
"@babel/cli": "^7.17.6", | ||
"@babel/core": "^7.17.9", | ||
"@babel/eslint-parser": "^7.17.0", | ||
"@babel/plugin-proposal-object-rest-spread": "^7.17.3", | ||
"@babel/plugin-transform-object-assign": "^7.16.7", | ||
"@babel/plugin-transform-react-display-name": "^7.16.7", | ||
"@babel/plugin-transform-react-jsx": "^7.17.3", | ||
"@babel/preset-env": "^7.16.11", | ||
"@rollup/plugin-commonjs": "^21.0.3", | ||
"@rollup/plugin-node-resolve": "^13.2.0", | ||
"@rollup/plugin-replace": "^4.0.0", | ||
"@testing-library/jest-dom": "^5.16.4", | ||
"@testing-library/jest-native": "^4.0.4", | ||
"@testing-library/react": "^12.1.2", | ||
"@testing-library/react-hooks": "^7.0.2", | ||
"@testing-library/react-native": "^9.0.0", | ||
"babel-jest": "^27.4.5", | ||
"@testing-library/react": "^13.0.1", | ||
"@testing-library/react-hooks": "^8.0.0", | ||
"@testing-library/react-native": "^9.1.0", | ||
"babel-jest": "^27.5.1", | ||
"cross-env": "^7.0.3", | ||
"es3ify": "^0.2.2", | ||
"eslint": "^8.4.1", | ||
"eslint-plugin-import": "^2.25.3", | ||
"eslint-plugin-react": "^7.27.1", | ||
"eslint-plugin-react-hooks": "^4.3.0", | ||
"glob": "^7.2.0", | ||
"jest": "^27.4.5", | ||
"npm-check-updates": "^12.0.3", | ||
"react": "^16.8.6", | ||
"react-dom": "^17.0.2", | ||
"react-native": "^0.66.4", | ||
"react-test-renderer": "^17.0.2", | ||
"eslint": "^8.13.0", | ||
"eslint-plugin-import": "^2.26.0", | ||
"eslint-plugin-react": "^7.29.4", | ||
"eslint-plugin-react-hooks": "^4.4.0", | ||
"glob": "^8.0.1", | ||
"jest": "^27.5.1", | ||
"metro-babel-register": "^0.70.1", | ||
"metro-react-native-babel-preset": "^0.70.1", | ||
"npm-check-updates": "^12.5.9", | ||
"react": "^18.0.0", | ||
"react-dom": "^18.0.0", | ||
"react-native": "^0.68.0", | ||
"react-test-renderer": "^18.0.0", | ||
"rimraf": "^3.0.2", | ||
"rollup": "^2.61.1", | ||
"rollup": "^2.70.1", | ||
"rollup-plugin-babel": "^4.4.0", | ||
@@ -85,0 +88,0 @@ "rollup-plugin-terser": "^7.0.2" |
@@ -300,2 +300,15 @@ React Singleton Hook | ||
### Unmounting hooks when there are no consumers | ||
You can pass the last optional parameter `options` to the `singletonHook` to | ||
configure if the hook should be unmounted when no one consumes it: | ||
```js | ||
const useHook = singletonHook( | ||
initVal, | ||
() => { /*hook body*/ }, | ||
{ unmountIfNoConsumers: true } | ||
); | ||
``` | ||
## React Native | ||
@@ -302,0 +315,0 @@ To use this library with react-native you always have to mount `SingletonHooksContainer` manually. |
@@ -11,3 +11,9 @@ import React, { useState, useEffect } from 'react'; | ||
let mountQueue = []; | ||
const mountIntoContainerDefault = (item) => { mountQueue.push(item); }; | ||
const mountIntoContainerDefault = (item) => { | ||
mountQueue.push(item); | ||
return () => { | ||
throw new Error('Can not unmount container! It is like a bug in react-singleton-hook library, because of unmountIfNoConsumers: true'); | ||
// mountQueue = mountQueue.filter(i => i !== item); | ||
}; | ||
}; | ||
let mountIntoContainer = mountIntoContainerDefault; | ||
@@ -29,3 +35,8 @@ | ||
useEffect(() => { | ||
mountIntoContainer = item => setHooks(hooks => [...hooks, item]); | ||
mountIntoContainer = item => { | ||
setHooks(hooks => [...hooks, item]); | ||
return () => { | ||
setHooks(hooks => hooks.filter(i => i !== item)); | ||
}; | ||
}; | ||
setHooks(mountQueue); | ||
@@ -43,3 +54,3 @@ }, []); | ||
} | ||
mountIntoContainer(hook); | ||
return mountIntoContainer(hook); | ||
}; | ||
@@ -46,0 +57,0 @@ |
@@ -5,7 +5,11 @@ import { useEffect, useState } from 'react'; | ||
export const singletonHook = (initValue, useHookBody) => { | ||
export const singletonHook = (initValue, useHookBody, options = {}) => { | ||
let mounted = false; | ||
let removeHook = undefined; | ||
let initStateCalculated = false; | ||
let lastKnownState = undefined; | ||
let consumers = []; | ||
let { | ||
unmountIfNoConsumers = false | ||
} = options; | ||
@@ -31,3 +35,3 @@ const applyStateChange = (newState) => { | ||
mounted = true; | ||
addHook({ initValue, useHookBody, applyStateChange }); | ||
removeHook = addHook({ initValue, useHookBody, applyStateChange }); | ||
} | ||
@@ -39,3 +43,9 @@ | ||
} | ||
return () => { consumers.splice(consumers.indexOf(setState), 1); }; | ||
return () => { | ||
consumers.splice(consumers.indexOf(setState), 1); | ||
if (consumers.length === 0 && unmountIfNoConsumers) { | ||
removeHook(); | ||
mounted = false; | ||
} | ||
}; | ||
@@ -42,0 +52,0 @@ // eslint-disable-next-line react-hooks/exhaustive-deps |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
48079
729
319
36