use-context-selector
Advanced tools
Comparing version 0.2.0 to 0.3.0
@@ -5,2 +5,6 @@ # Change Log | ||
## [0.3.0] - 2019-07-20 | ||
### Changed | ||
- No useLayoutEffect for invoking listeners (which leads de-opt sync mode) | ||
## [0.2.0] - 2019-07-07 | ||
@@ -7,0 +11,0 @@ ### Changed |
@@ -1,2 +0,2 @@ | ||
import e from"react";var r=function(e){return e+1},t=function(){return 0},n=function(e){return e},u=Symbol("CONTEXT_LISTENERS"),c=function(r){var n=e.createContext(r,t),c=new Set;return n[u]=c,n.Provider=function(r,t){return e.memo(function(n){var u=n.value,c=n.children;return e.useLayoutEffect(function(){t.forEach(function(e){return e(u)})},[u]),e.createElement(r,{value:u},c)})}(n.Provider,c),delete n.Consumer,n},o=function(t,n){var c=t[u];if(!c)throw new Error("useContextSelector requires special context");var o=e.useReducer(r,0)[1],f=e.useContext(t),i=n(f),a=e.useRef(null);return e.useLayoutEffect(function(){a.current={selector:n,value:f,selected:i}}),e.useLayoutEffect(function(){var e=function(e){try{if(a.current.value===e||Object.is(a.current.selected,a.current.selector(e)))return}catch(e){}a.current.value=e,o()};return c.add(e),function(){c.delete(e)}},[o,c]),i},f=function(e){return o(e,n)};export{c as createContext,f as useContext,o as useContextSelector}; | ||
import e from"react";var r=function(e){return e+1},t=function(){return 0},n=function(e){return e},u=Symbol("CONTEXT_LISTENERS"),c=function(r){var n=e.createContext(r,t),c=new Set;return n[u]=c,n.Provider=function(r,t){return e.memo(function(n){var u=n.value,c=n.children;return t.forEach(function(e){return e(u)}),e.createElement(r,{value:u},c)})}(n.Provider,c),delete n.Consumer,n},o=function(t,n){var c=t[u];if(!c)throw new Error("useContextSelector requires special context");var o=e.useReducer(r,0)[1],f=e.useContext(t),i=n(f),a=e.useRef(null);return e.useLayoutEffect(function(){a.current={selector:n,value:f,selected:i}}),e.useLayoutEffect(function(){var e=function(e){try{if(a.current.value===e||Object.is(a.current.selected,a.current.selector(e)))return}catch(e){}o()};return c.add(e),function(){c.delete(e)}},[o,c]),i},f=function(e){return o(e,n)};export{c as createContext,f as useContext,o as useContextSelector}; | ||
//# sourceMappingURL=index.esm.js.map |
@@ -1,2 +0,2 @@ | ||
var e,t=(e=require("react"))&&"object"==typeof e&&"default"in e?e.default:e,r=function(e){return e+1},n=function(){return 0},u=function(e){return e},c=Symbol("CONTEXT_LISTENERS"),o=function(e,n){var u=e[c];if(!u)throw new Error("useContextSelector requires special context");var o=t.useReducer(r,0)[1],f=t.useContext(e),a=n(f),i=t.useRef(null);return t.useLayoutEffect(function(){i.current={selector:n,value:f,selected:a}}),t.useLayoutEffect(function(){var e=function(e){try{if(i.current.value===e||Object.is(i.current.selected,i.current.selector(e)))return}catch(e){}i.current.value=e,o()};return u.add(e),function(){u.delete(e)}},[o,u]),a};exports.createContext=function(e){var r=t.createContext(e,n),u=new Set;return r[c]=u,r.Provider=function(e,r){return t.memo(function(n){var u=n.value,c=n.children;return t.useLayoutEffect(function(){r.forEach(function(e){return e(u)})},[u]),t.createElement(e,{value:u},c)})}(r.Provider,u),delete r.Consumer,r},exports.useContext=function(e){return o(e,u)},exports.useContextSelector=o; | ||
var e,t=(e=require("react"))&&"object"==typeof e&&"default"in e?e.default:e,r=function(e){return e+1},n=function(){return 0},u=function(e){return e},o=Symbol("CONTEXT_LISTENERS"),c=function(e,n){var u=e[o];if(!u)throw new Error("useContextSelector requires special context");var c=t.useReducer(r,0)[1],f=t.useContext(e),i=n(f),a=t.useRef(null);return t.useLayoutEffect(function(){a.current={selector:n,value:f,selected:i}}),t.useLayoutEffect(function(){var e=function(e){try{if(a.current.value===e||Object.is(a.current.selected,a.current.selector(e)))return}catch(e){}c()};return u.add(e),function(){u.delete(e)}},[c,u]),i};exports.createContext=function(e){var r=t.createContext(e,n),u=new Set;return r[o]=u,r.Provider=function(e,r){return t.memo(function(n){var u=n.value,o=n.children;return r.forEach(function(e){return e(u)}),t.createElement(e,{value:u},o)})}(r.Provider,u),delete r.Consumer,r},exports.useContext=function(e){return c(e,u)},exports.useContextSelector=c; | ||
//# sourceMappingURL=index.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&&t.hasOwnProperty("default")?t.default:t;var r=function(e){return e+1},n=function(){return 0},u=function(e){return e},o=Symbol("CONTEXT_LISTENERS"),c=function(e,n){var u=e[o];if(!u)throw new Error("useContextSelector requires special context");var c=t.useReducer(r,0)[1],f=t.useContext(e),i=n(f),a=t.useRef(null);return t.useLayoutEffect(function(){a.current={selector:n,value:f,selected:i}}),t.useLayoutEffect(function(){var e=function(e){try{if(a.current.value===e||Object.is(a.current.selected,a.current.selector(e)))return}catch(e){}a.current.value=e,c()};return u.add(e),function(){u.delete(e)}},[c,u]),i};e.createContext=function(e){var r=t.createContext(e,n),u=new Set;return r[o]=u,r.Provider=function(e,r){return t.memo(function(n){var u=n.value,o=n.children;return t.useLayoutEffect(function(){r.forEach(function(e){return e(u)})},[u]),t.createElement(e,{value:u},o)})}(r.Provider,u),delete r.Consumer,r},e.useContext=function(e){return c(e,u)},e.useContextSelector=c}); | ||
!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&&t.hasOwnProperty("default")?t.default:t;var r=function(e){return e+1},n=function(){return 0},u=function(e){return e},o=Symbol("CONTEXT_LISTENERS"),c=function(e,n){var u=e[o];if(!u)throw new Error("useContextSelector requires special context");var c=t.useReducer(r,0)[1],f=t.useContext(e),i=n(f),a=t.useRef(null);return t.useLayoutEffect(function(){a.current={selector:n,value:f,selected:i}}),t.useLayoutEffect(function(){var e=function(e){try{if(a.current.value===e||Object.is(a.current.selected,a.current.selector(e)))return}catch(e){}c()};return u.add(e),function(){u.delete(e)}},[c,u]),i};e.createContext=function(e){var r=t.createContext(e,n),u=new Set;return r[o]=u,r.Provider=function(e,r){return t.memo(function(n){var u=n.value,o=n.children;return r.forEach(function(e){return e(u)}),t.createElement(e,{value:u},o)})}(r.Provider,u),delete r.Consumer,r},e.useContext=function(e){return c(e,u)},e.useContextSelector=c}); | ||
//# sourceMappingURL=index.umd.js.map |
{ | ||
"name": "use-context-selector", | ||
"description": "React useContextSelector hook in userland", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"author": "Daishi Kato", | ||
@@ -36,11 +36,11 @@ "repository": { | ||
"devDependencies": { | ||
"@babel/cli": "^7.5.0", | ||
"@babel/core": "^7.5.0", | ||
"@babel/preset-env": "^7.5.0", | ||
"@babel/cli": "^7.5.5", | ||
"@babel/core": "^7.5.5", | ||
"@babel/preset-env": "^7.5.5", | ||
"@babel/preset-react": "^7.0.0", | ||
"@testing-library/react": "^8.0.4", | ||
"@testing-library/react": "^8.0.5", | ||
"@types/react": "^16.8.23", | ||
"@types/react-dom": "^16.8.4", | ||
"@typescript-eslint/eslint-plugin": "^1.11.0", | ||
"@typescript-eslint/parser": "^1.11.0", | ||
"@typescript-eslint/eslint-plugin": "^1.12.0", | ||
"@typescript-eslint/parser": "^1.12.0", | ||
"babel-core": "^7.0.0-bridge.0", | ||
@@ -51,3 +51,3 @@ "babel-eslint": "^10.0.2", | ||
"eslint-config-airbnb": "^17.1.1", | ||
"eslint-plugin-import": "^2.18.0", | ||
"eslint-plugin-import": "^2.18.2", | ||
"eslint-plugin-jsx-a11y": "^6.2.3", | ||
@@ -62,5 +62,5 @@ "eslint-plugin-react": "^7.14.2", | ||
"ts-loader": "^6.0.4", | ||
"typescript": "^3.5.2", | ||
"webpack": "^4.35.2", | ||
"webpack-cli": "^3.3.5", | ||
"typescript": "^3.5.3", | ||
"webpack": "^4.36.1", | ||
"webpack-cli": "^3.3.6", | ||
"webpack-dev-server": "^3.7.2" | ||
@@ -75,3 +75,5 @@ }, | ||
"@babel/preset-env", | ||
{ "targets": "> 0.2%, not dead" } | ||
{ | ||
"targets": "> 0.2%, not dead" | ||
} | ||
], | ||
@@ -78,0 +80,0 @@ "@babel/preset-react" |
@@ -16,3 +16,3 @@ # use-context-selector | ||
[useContextSelector](https://github.com/gnoff/rfcs/pull/2) is recently proposed. | ||
[useContextSelector](https://github.com/reactjs/rfcs/pull/119) is recently proposed. | ||
While waiting for the process, this library provides the API in userland. | ||
@@ -45,5 +45,5 @@ | ||
<div> | ||
{Math.random()} | ||
<span>Count1: {count1}</span> | ||
<button type="button" onClick={increment}>+1</button> | ||
{Math.random()} | ||
</div> | ||
@@ -62,5 +62,5 @@ ); | ||
<div> | ||
{Math.random()} | ||
<span>Count2: {count2}</span> | ||
<button type="button" onClick={increment}>+1</button> | ||
{Math.random()} | ||
</div> | ||
@@ -92,3 +92,3 @@ ); | ||
React context by nature triggers propagation of component re-rendering | ||
if a value is changed. To avoid this, this libraries use undocumented | ||
if a value is changed. To avoid this, this library uses undocumented | ||
feature of `calculateChangedBits`. It then uses a subscription model | ||
@@ -99,5 +99,6 @@ to force update when a component needs to re-render. | ||
- Subscriptions are context-based. So, even if there are multiple context providers in a component tree, all components are subscribed to all providers. This may lead false positives (extra re-renders). | ||
- Subscriptions are per-context basis. So, even if there are multiple context providers in a component tree, all components are subscribed to all providers. This may lead false positives (extra re-renders). | ||
- In order to stop propagation, `children` of a context provider has to be either created outside of the provider or memoized with `React.memo`. | ||
- Context consumers are not supported. | ||
- The "stale props" issue can't be solved in userland. (workaround with try-catch) | ||
@@ -104,0 +105,0 @@ ## Examples |
@@ -15,5 +15,7 @@ import React from 'react'; | ||
const createProvider = (OrigProvider, listeners) => React.memo(({ value, children }) => { | ||
React.useLayoutEffect(() => { | ||
listeners.forEach(listener => listener(value)); | ||
}, [value]); | ||
// we call listeners in render intentionally. | ||
// listeners are not technically pure, but | ||
// otherwise we can't get benefits from concurrent mode. | ||
// we make sure to work with double or more invocation of listeners. | ||
listeners.forEach(listener => listener(value)); | ||
return React.createElement(OrigProvider, { value }, children); | ||
@@ -60,3 +62,2 @@ }); | ||
} | ||
ref.current.value = nextValue; | ||
forceUpdate(); | ||
@@ -63,0 +64,0 @@ }; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
22886
86
119