Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

use-context-selector

Package Overview
Dependencies
Maintainers
1
Versions
52
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

use-context-selector - npm Package Compare versions

Comparing version 1.1.4 to 1.2.0

src/batchedUpdates.js

4

CHANGELOG.md

@@ -5,2 +5,6 @@ # Change Log

## [1.2.0] - 2020-10-01
### Added
- useContextUpdate for state branching support
## [1.1.4] - 2020-09-22

@@ -7,0 +11,0 @@ ### Added

2

dist/index.modern.js

@@ -1,2 +0,2 @@

import e from"react";const r=Symbol(),t=Symbol(),n="undefined"==typeof window||/ServerSideRendering/.test(window.navigator&&window.navigator.userAgent)?e=>e():e.useLayoutEffect,o=o=>{const c=e.createContext(o,()=>0);var u,i;return c[r]=new Set,c[t]=c.Provider,c.Provider=(u=c.Provider,i=c[r],e.memo(({value:r,children:t})=>("production"!==process.env.NODE_ENV?n(()=>{i.forEach(e=>{e(r)})}):i.forEach(e=>{e(r)}),e.createElement(u,{value:r},t)))),delete c.Consumer,c},c=(t,o)=>{const c=t[r];if("production"!==process.env.NODE_ENV&&!c)throw new Error("useContextSelector requires special context");const[,u]=e.useReducer(e=>e+1,0),i=e.useContext(t),s=o(i),d=e.useRef(null);return n(()=>{d.current={f:o,v:i,s}}),n(()=>{const e=e=>{try{if(d.current.v===e||Object.is(d.current.s,d.current.f(e)))return}catch(e){}u()};return c.add(e),()=>{c.delete(e)}},[c]),s},u=e=>e,i=e=>c(e,u),s=({context:r,value:n,children:o})=>{const{[t]:c}=r;if("production"!==process.env.NODE_ENV&&!c)throw new Error("BridgeProvider requires special context");return e.createElement(c,{value:n},o)};export{s as BridgeProvider,o as createContext,i as useContext,c as useContextSelector,n as useIsoLayoutEffect};
import e from"react";import{unstable_runWithPriority as r,unstable_NormalPriority as t}from"scheduler";import{unstable_batchedUpdates as n}from"react-dom";const c="v",o="p",u="l",s="u",i=Symbol(),a=Symbol(),d="undefined"==typeof window||/ServerSideRendering/.test(window.navigator&&window.navigator.userAgent)?e=>e():e.useLayoutEffect,l=l=>{const f=e.createContext(l,()=>0);var v;return f[a]=f.Provider,f.Provider=(v=f.Provider,e.memo(({value:a,children:l})=>{const[f,p]=e.useState(0),m=e.useRef(0),E=e.useRef();E.current||(E.current=new Set);const w=e.useCallback(e=>{n(()=>(m.current+=1,p(m.current),E.current.forEach(e=>e(m.current)),e()))},[]);return d(()=>{m.current+=1,p(m.current),r(t,()=>{E.current.forEach(e=>{e(m.current,a)})})},[a]),e.createElement(v,{value:{[i]:{[c]:a,[o]:f,[u]:E.current,[s]:w}}},l)})),delete f.Consumer,f},f=(r,t)=>{const n=e.useContext(r)[i];if("production"!==process.env.NODE_ENV&&!n)throw new Error("useContextSelector requires special context");const{[c]:s,[o]:a,[u]:l}=n,f=t(s),v=e.useRef(null);d(()=>{v.current={f:t,v:s,s:f}});const[,p]=e.useReducer((e,r)=>{if(a<r)return e+1;try{if(v.current.v===s||Object.is(v.current.s,v.current.f(s)))return e}catch(e){}return e+1},0);return d(()=>{const e=(e,r)=>{try{if(v.current.v===r||Object.is(v.current.s,v.current.f(r)))return}catch(e){}p(e)};return l.add(e),()=>{l.delete(e)}},[l]),f},v=e=>e,p=e=>f(e,v),m=r=>{const t=e.useContext(r)[i];if("production"!==process.env.NODE_ENV&&!t)throw new Error("useContextUpdate requires special context");const{[s]:n}=t;return n},E=({context:r,value:t,children:n})=>{const{[a]:c}=r;if("production"!==process.env.NODE_ENV&&!c)throw new Error("BridgeProvider requires special context");return e.createElement(c,{value:t},n)};export{E as BridgeProvider,l as createContext,p as useContext,f as useContextSelector,m as useContextUpdate,d as useIsoLayoutEffect};
//# sourceMappingURL=index.modern.js.map

@@ -1,2 +0,2 @@

!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],t):t((e=e||self).useContextSelector={},e.react)}(this,function(e,t){t=t&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t;var r=Symbol(),n=Symbol(),o="undefined"==typeof window||/ServerSideRendering/.test(window.navigator&&window.navigator.userAgent)?function(e){return e()}:t.useLayoutEffect,u=function(e,n){var u=e[r];if("production"!==process.env.NODE_ENV&&!u)throw new Error("useContextSelector requires special context");var c=t.useReducer(function(e){return e+1},0)[1],i=t.useContext(e),f=n(i),a=t.useRef(null);return o(function(){a.current={f:n,v:i,s:f}}),o(function(){var e=function(e){try{if(a.current.v===e||Object.is(a.current.s,a.current.f(e)))return}catch(e){}c()};return u.add(e),function(){u.delete(e)}},[u]),f},c=function(e){return e};e.BridgeProvider=function(e){var r=e.value,o=e.children,u=e.context[n];if("production"!==process.env.NODE_ENV&&!u)throw new Error("BridgeProvider requires special context");return t.createElement(u,{value:r},o)},e.createContext=function(e){var u,c,i=t.createContext(e,function(){return 0});return i[r]=new Set,i[n]=i.Provider,i.Provider=(u=i.Provider,c=i[r],t.memo(function(e){var r=e.value,n=e.children;return"production"!==process.env.NODE_ENV?o(function(){c.forEach(function(e){e(r)})}):c.forEach(function(e){e(r)}),t.createElement(u,{value:r},n)})),delete i.Consumer,i},e.useContext=function(e){return u(e,c)},e.useContextSelector=u,e.useIsoLayoutEffect=o});
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports,require("react"),require("scheduler"),require("react-dom")):"function"==typeof define&&define.amd?define(["exports","react","scheduler","react-dom"],r):r((e=e||self).useContextSelector={},e.react,e.scheduler,e.reactDom)}(this,function(e,r,t,n){r=r&&Object.prototype.hasOwnProperty.call(r,"default")?r.default:r;var u=Symbol(),o=Symbol(),c="undefined"==typeof window||/ServerSideRendering/.test(window.navigator&&window.navigator.userAgent)?function(e){return e()}:r.useLayoutEffect,i=function(e,t){var n=r.useContext(e)[u];if("production"!==process.env.NODE_ENV&&!n)throw new Error("useContextSelector requires special context");var o=n.v,i=n.p,a=n.l,f=t(o),s=r.useRef(null);c(function(){s.current={f:t,v:o,s:f}});var d=r.useReducer(function(e,r){if(i<r)return e+1;try{if(s.current.v===o||Object.is(s.current.s,s.current.f(o)))return e}catch(e){}return e+1},0)[1];return c(function(){var e=function(e,r){try{if(s.current.v===r||Object.is(s.current.s,s.current.f(r)))return}catch(e){}d(e)};return a.add(e),function(){a.delete(e)}},[a]),f},a=function(e){return e};e.BridgeProvider=function(e){var t=e.value,n=e.children,u=e.context[o];if("production"!==process.env.NODE_ENV&&!u)throw new Error("BridgeProvider requires special context");return r.createElement(u,{value:t},n)},e.createContext=function(e){var i,a=r.createContext(e,function(){return 0});return a[o]=a.Provider,a.Provider=(i=a.Provider,r.memo(function(e){var o,a,f=e.value,s=e.children,d=r.useState(0),l=d[0],v=d[1],p=r.useRef(0),x=r.useRef();x.current||(x.current=new Set);var h=r.useCallback(function(e){n.unstable_batchedUpdates(function(){return p.current+=1,v(p.current),x.current.forEach(function(e){return e(p.current)}),e()})},[]);c(function(){p.current+=1,v(p.current),t.unstable_runWithPriority(t.unstable_NormalPriority,function(){x.current.forEach(function(e){e(p.current,f)})})},[f]);var E=((o={}).v=f,o.p=l,o.l=x.current,o.u=h,o);return r.createElement(i,{value:(a={},a[u]=E,a)},s)})),delete a.Consumer,a},e.useContext=function(e){return i(e,a)},e.useContextSelector=i,e.useContextUpdate=function(e){var t=r.useContext(e)[u];if("production"!==process.env.NODE_ENV&&!t)throw new Error("useContextUpdate requires special context");return t.u},e.useIsoLayoutEffect=c});
//# sourceMappingURL=index.umd.js.map
{
"name": "use-context-selector",
"description": "React useContextSelector hook in userland",
"version": "1.1.4",
"version": "1.2.0",
"author": "Daishi Kato",

@@ -37,28 +37,29 @@ "repository": {

"devDependencies": {
"@babel/cli": "^7.10.5",
"@babel/core": "^7.11.0",
"@babel/preset-env": "^7.11.0",
"@babel/cli": "^7.11.6",
"@babel/core": "^7.11.6",
"@babel/preset-env": "^7.11.5",
"@babel/preset-react": "^7.10.4",
"@testing-library/react": "^10.4.7",
"@types/react": "^16.9.44",
"@testing-library/react": "^11.0.4",
"@types/react": "^16.9.49",
"@types/react-dom": "^16.9.8",
"@typescript-eslint/eslint-plugin": "^3.7.1",
"@typescript-eslint/parser": "^3.7.1",
"@typescript-eslint/eslint-plugin": "^4.3.0",
"@typescript-eslint/parser": "^4.3.0",
"babel-loader": "^8.1.0",
"documentation": "^13.0.2",
"eslint": "^7.6.0",
"eslint": "^7.10.0",
"eslint-config-airbnb": "^18.2.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsx-a11y": "^6.3.1",
"eslint-plugin-react": "^7.20.5",
"eslint-plugin-react-hooks": "^4.0.8",
"html-webpack-plugin": "^4.3.0",
"jest": "^26.2.2",
"microbundle": "^0.12.3",
"eslint-plugin-react": "^7.21.2",
"eslint-plugin-react-hooks": "^4.1.2",
"html-webpack-plugin": "^4.5.0",
"jest": "^26.4.2",
"microbundle": "^0.12.4",
"npm-run-all": "^4.1.5",
"react": "experimental",
"react-dom": "experimental",
"ts-loader": "^8.0.2",
"typescript": "^3.9.7",
"webpack": "^4.44.1",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"scheduler": "^0.19.1",
"ts-loader": "^8.0.4",
"typescript": "^4.0.3",
"webpack": "^4.44.2",
"webpack-cli": "^3.3.12",

@@ -68,4 +69,11 @@ "webpack-dev-server": "^3.11.0"

"peerDependencies": {
"react": ">=16.8.0"
"react": ">=16.8.0",
"scheduler": ">=0.19.0",
"react-dom": "*"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
}
},
"babel": {

@@ -72,0 +80,0 @@ "presets": [

@@ -149,2 +149,21 @@ # use-context-selector

### useContextUpdate
This hook returns an update function that accepts a thunk function
Use this for a function that will change a value.
#### Parameters
- `context`
#### Examples
```javascript
import { useContextUpdate } from 'use-context-selector';
const update = useContextUpdate();
update(() => setState(...));
```
### BridgeProvider

@@ -169,3 +188,3 @@

{children}
</Bidge>
</BridgeProvider>
</Renderer>

@@ -172,0 +191,0 @@ );

import React from 'react';
import {
unstable_NormalPriority as NormalPriority,
unstable_runWithPriority as runWithPriority,
} from 'scheduler';
const CONTEXT_LISTENERS = Symbol();
import { batchedUpdates } from './batchedUpdates';
const VALUE_PROP = 'v';
const VERSION_PROP = 'p';
const LISTENERS_PROP = 'l';
const UPDATE_PROP = 'u';
const CONTEXT_VALUE = Symbol();
const ORIGINAL_PROVIDER = Symbol();

@@ -13,24 +24,40 @@

const createProvider = (OrigProvider, listeners) => React.memo(({ value, children }) => {
if (process.env.NODE_ENV !== 'production') {
// we use layout effect to eliminate warnings.
// but, this leads tearing with startTransition.
// eslint-disable-next-line react-hooks/rules-of-hooks
const createProvider = (OrigProvider) => (
React.memo(({ value, children }) => {
const [version, setVersion] = React.useState(0);
const versionRef = React.useRef(0);
const listeners = React.useRef();
if (!listeners.current) {
listeners.current = new Set();
}
const update = React.useCallback((thunk) => {
batchedUpdates(() => {
versionRef.current += 1;
setVersion(versionRef.current);
listeners.current.forEach((listener) => listener(versionRef.current));
return thunk();
});
}, []);
useIsoLayoutEffect(() => {
listeners.forEach((listener) => {
listener(value);
versionRef.current += 1;
setVersion(versionRef.current);
runWithPriority(NormalPriority, () => {
listeners.current.forEach((listener) => {
listener(versionRef.current, value);
});
});
});
} else {
// we call listeners in render for optimization.
// although this is not a recommended pattern,
// so far this is only the way to make it as expected.
// we are looking for better solutions.
// https://github.com/dai-shi/use-context-selector/pull/12
listeners.forEach((listener) => {
listener(value);
});
}
return React.createElement(OrigProvider, { value }, children);
});
}, [value]);
const contextValue = {
[VALUE_PROP]: value,
[VERSION_PROP]: version,
[LISTENERS_PROP]: listeners.current,
[UPDATE_PROP]: update,
};
return React.createElement(
OrigProvider,
{ value: { [CONTEXT_VALUE]: contextValue } },
children,
);
})
);

@@ -47,8 +74,6 @@ /**

const context = React.createContext(defaultValue, () => 0);
// shared listeners (not ideal)
context[CONTEXT_LISTENERS] = new Set();
// original provider
context[ORIGINAL_PROVIDER] = context.Provider;
// hacked provider
context.Provider = createProvider(context.Provider, context[CONTEXT_LISTENERS]);
context.Provider = createProvider(context.Provider);
// no support for consumer

@@ -70,10 +95,13 @@ delete context.Consumer;

export const useContextSelector = (context, selector) => {
const listeners = context[CONTEXT_LISTENERS];
const contextValue = React.useContext(context)[CONTEXT_VALUE];
if (process.env.NODE_ENV !== 'production') {
if (!listeners) {
if (!contextValue) {
throw new Error('useContextSelector requires special context');
}
}
const [, forceUpdate] = React.useReducer((c) => c + 1, 0);
const value = React.useContext(context);
const {
[VALUE_PROP]: value,
[VERSION_PROP]: version,
[LISTENERS_PROP]: listeners,
} = contextValue;
const selected = selector(value);

@@ -88,4 +116,18 @@ const ref = React.useRef(null);

});
const [, checkUpdate] = React.useReducer((c, v) => {
if (version < v) {
return c + 1; // schedule update
}
try {
if (ref.current.v === value
|| Object.is(ref.current.s, ref.current.f(value))) {
return c; // bail out
}
} catch (e) {
// ignored (stale props or some other reason)
}
return c + 1;
}, 0);
useIsoLayoutEffect(() => {
const callback = (nextValue) => {
const callback = (nextVersion, nextValue) => {
try {

@@ -99,3 +141,3 @@ if (ref.current.v === nextValue

}
forceUpdate();
checkUpdate(nextVersion);
};

@@ -123,2 +165,24 @@ listeners.add(callback);

/**
* This hook returns an update function that accepts a thunk function
*
* Use this for a function that will change a value.
*
* @example
* import { useContextUpdate } from 'use-context-selector';
*
* const update = useContextUpdate();
* update(() => setState(...));
*/
export const useContextUpdate = (context) => {
const contextValue = React.useContext(context)[CONTEXT_VALUE];
if (process.env.NODE_ENV !== 'production') {
if (!contextValue) {
throw new Error('useContextUpdate requires special context');
}
}
const { [UPDATE_PROP]: update } = contextValue;
return update;
};
/**
* This is a Provider component for bridging multiple react roots

@@ -136,3 +200,3 @@ * @param props

* {children}
* </Bidge>
* </BridgeProvider>
* </Renderer>

@@ -139,0 +203,0 @@ * );

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc