react-hooks-global-state
Advanced tools
Comparing version 2.0.0-alpha.3 to 2.0.0-alpha.4
# Change Log | ||
## [Unreleased] | ||
### Changed | ||
- Re-implemented with zustand as a dependency | ||
- BREAKING CHANGE: `useGlobalState` created with `createStore` doesn't return the second part of the tuple | ||
### Removed | ||
- BREAKING CHANGE: drop reduxDevToolsExt | ||
- Reference implementation in `examples/08_thunk/src/devtools.ts` | ||
## [1.0.2] - 2021-08-14 | ||
### Changed | ||
- Fix package.json properly for ESM | ||
## [1.0.1] - 2020-07-04 | ||
@@ -6,0 +16,0 @@ ### Changed |
@@ -1,2 +0,2 @@ | ||
import{unstable_createMutableSource as t,useCallback as e,unstable_useMutableSource as r}from"react";const o=(t,e)=>"function"==typeof e?e(t):e,n=(t,e)=>{if(!t.includes(e))throw new Error(`'${e}' not found. It must be provided in initialState as a property key.`)};function s(e,r){const s=Object.keys(e);let a=e;const c=(()=>{const t=new Map;return s.forEach(e=>{t.set(e,new Set)}),t.set(null,new Set),t})(),u=(t,e)=>{s.forEach(r=>{t[r]!==e[r]&&c.get(r).forEach(t=>{t()})}),c.get(null).forEach(t=>{t()})},i={getState:()=>a,setState:t=>{const e=a;a=o(e,t),u(e,a)},getStateByKey:t=>("production"!==process.env.NODE_ENV&&n(s,t),a[t]),setStateByKey:(t,e)=>{var r;"production"!==process.env.NODE_ENV&&n(s,t),r=a,a={...r,[t]:o(r[t],e)},c.get(t).forEach(t=>{t()}),c.get(null).forEach(t=>{t()})},dispatch:t=>{if(!r)throw new Error("no reducer specified");const e=a;return a=r(e,t),u(e,a),t},subscribe:(t,e)=>{const r=c.get(t);return r.add(e),()=>{r.delete(e)}},mutableSource:void 0};return i.mutableSource=t(i,()=>a),i}function a(t,o){const n=e(t=>o?t.getStateByKey(o):t.getState(),[o]),s=e((t,e)=>t.subscribe(o||null,e),[o]);return[r(t.mutableSource,n,s),e(e=>{o?t.setStateByKey(o,e):t.setState(e)},[t,o])]}const c=t=>{const e=s(t);return{useGlobalState:t=>a(e,t),getGlobalState:e.getStateByKey,setGlobalState:e.setStateByKey}},u=(t,e=t(void 0,{type:void 0}),r)=>{if(r)return r(u)(t,e);const o=s(e,t);return{useGlobalState:t=>a(o,t),getState:o.getState,setState:o.setState,dispatch:o.dispatch}},i=()=>{if(!window.__REDUX_DEVTOOLS_EXTENSION__)return t=>t;const{before:t,after:e}=(()=>{let t,e;return{before:r=>(o,n,s)=>{if(t=o,e=n,s)return s(r)(o,n);const a=r(o,n);return{...a,useGlobalState:t=>{const[e]=a.useGlobalState(t);return[e,()=>{throw new Error("Update is not allowed when using DevTools")}]}}},after:r=>(o,n,s)=>{if(s)return s(r)(o,n);const a=r(t,e);let c={...o(n,{type:"@@redux/INIT"}),...e};const u=[];return{...a,getState:()=>c,dispatch:t=>(c=o(c,t),a.setState(c.computedStates[c.currentStateIndex].state),u.forEach(t=>t()),t),subscribe:t=>(u.push(t),()=>{const e=u.indexOf(t);u.splice(e,1)})}}}})();return((...t)=>t.reduce((t,e)=>(...r)=>t(e(...r))))(t,window.__REDUX_DEVTOOLS_EXTENSION__(),e)};export{s as createAtom,c as createGlobalState,u as createStore,i as reduxDevToolsExt,a as useAtom}; | ||
//# sourceMappingURL=index.modern.js.map | ||
import{useCallback as t}from"react";import e from"zustand";import{redux as o}from"zustand/middleware";const r=(t,e)=>{if(!t.includes(e))throw new Error(`'${e}' not found. It must be provided in initialState as a property key.`)},n=o=>{const n=e(()=>o),s=Object.keys(o),i=(t,e)=>{"production"!==process.env.NODE_ENV&&r(s,t),n.setState(o=>{return{[t]:(r=o[t],n=e,"function"==typeof n?n(r):n)};var r,n})};return{useGlobalState:e=>{"production"!==process.env.NODE_ENV&&r(s,e);const o=t(t=>t[e],[e]);return[n(o),t(t=>i(e,t),[e])]},getGlobalState:t=>("production"!==process.env.NODE_ENV&&r(s,t),n.getState()[t]),setGlobalState:i}},s=(r,n=r(void 0,{type:void 0}),i)=>{if(i)return i(s)(r,n);const a=e(o(r,n)),p=Object.keys(n);return{useGlobalState:e=>{"production"!==process.env.NODE_ENV&&((t,e)=>{if(!t.includes(e))throw new Error(`'${e}' not found. It must be provided in initialState as a property key.`)})(p,e);const o=t(t=>t[e],[e]);return[a(o)]},getState:()=>a.getState(),dispatch:t=>a.dispatch(t)}};export{n as createGlobalState,s as createStore}; | ||
//# sourceMappingURL=index.modern.mjs.map |
@@ -1,2 +0,2 @@ | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],e):e((t=t||self).reactHooksGlobalState={},t.react)}(this,function(t,e){function n(){return(n=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(t[r]=n[r])}return t}).apply(this,arguments)}var r=function(t,e){return"function"==typeof e?e(t):e},u=function(t,e){if(!t.includes(e))throw new Error("'"+e+"' not found. It must be provided in initialState as a property key.")};function o(t,o){var a=Object.keys(t),c=t,i=function(){var t=new Map;return a.forEach(function(e){t.set(e,new Set)}),t.set(null,new Set),t}(),f=function(t,e){a.forEach(function(n){t[n]!==e[n]&&i.get(n).forEach(function(t){t()})}),i.get(null).forEach(function(t){t()})},s={getState:function(){return c},setState:function(t){var e=c;c=r(e,t),f(e,c)},getStateByKey:function(t){return"production"!==process.env.NODE_ENV&&u(a,t),c[t]},setStateByKey:function(t,e){var o,f;"production"!==process.env.NODE_ENV&&u(a,t),c=n({},o=c,((f={})[t]=r(o[t],e),f)),i.get(t).forEach(function(t){t()}),i.get(null).forEach(function(t){t()})},dispatch:function(t){if(!o)throw new Error("no reducer specified");var e=c;return c=o(e,t),f(e,c),t},subscribe:function(t,e){var n=i.get(t);return n.add(e),function(){n.delete(e)}},mutableSource:void 0};return s.mutableSource=e.unstable_createMutableSource(s,function(){return c}),s}function a(t,n){var r=e.useCallback(function(t){return n?t.getStateByKey(n):t.getState()},[n]),u=e.useCallback(function(t,e){return t.subscribe(n||null,e)},[n]);return[e.unstable_useMutableSource(t.mutableSource,r,u),e.useCallback(function(e){n?t.setStateByKey(n,e):t.setState(e)},[t,n])]}t.createAtom=o,t.createGlobalState=function(t){var e=o(t);return{useGlobalState:function(t){return a(e,t)},getGlobalState:e.getStateByKey,setGlobalState:e.setStateByKey}},t.createStore=function t(e,n,r){if(void 0===n&&(n=e(void 0,{type:void 0})),r)return r(t)(e,n);var u=o(n,e);return{useGlobalState:function(t){return a(u,t)},getState:u.getState,setState:u.setState,dispatch:u.dispatch}},t.reduxDevToolsExt=function(){return window.__REDUX_DEVTOOLS_EXTENSION__?function(){return[].slice.call(arguments).reduce(function(t,e){return function(){return t(e.apply(void 0,[].slice.call(arguments)))}})}(function(r){return function(u,o,a){if(t=u,e=o,a)return a(r)(u,o);var c=r(u,o);return n({},c,{useGlobalState:function(t){return[c.useGlobalState(t)[0],function(){throw new Error("Update is not allowed when using DevTools")}]}})}},window.__REDUX_DEVTOOLS_EXTENSION__(),function(r){return function(u,o,a){if(a)return a(r)(u,o);var c=r(t,e),i=n({},u(o,{type:"@@redux/INIT"}),e),f=[];return n({},c,{getState:function(){return i},dispatch:function(t){return i=u(i,t),c.setState(i.computedStates[i.currentStateIndex].state),f.forEach(function(t){return t()}),t},subscribe:function(t){return f.push(t),function(){var e=f.indexOf(t);f.splice(e,1)}}})}}):function(t){return t};var t,e},t.useAtom=a}); | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react"),require("zustand"),require("zustand/middleware")):"function"==typeof define&&define.amd?define(["exports","react","zustand","zustand/middleware"],e):e((t||self).reactHooksGlobalState={},t.react,t.zustand,t.middleware)}(this,function(t,e,n,r){function o(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var u=o(n),a=function(t,e){if(!t.includes(e))throw new Error("'"+e+"' not found. It must be provided in initialState as a property key.")};t.createGlobalState=function(t){var n=u.default(function(){return t}),r=Object.keys(t),o=function(t,e){"production"!==process.env.NODE_ENV&&a(r,t),n.setState(function(n){var r,o;return(r={})[t]="function"==typeof(o=e)?o(n[t]):o,r})};return{useGlobalState:function(t){"production"!==process.env.NODE_ENV&&a(r,t);var u=e.useCallback(function(e){return e[t]},[t]);return[n(u),e.useCallback(function(e){return o(t,e)},[t])]},getGlobalState:function(t){return"production"!==process.env.NODE_ENV&&a(r,t),n.getState()[t]},setGlobalState:o}},t.createStore=function t(n,o,a){if(void 0===o&&(o=n(void 0,{type:void 0})),a)return a(t)(n,o);var i=u.default(r.redux(n,o)),c=Object.keys(o);return{useGlobalState:function(t){"production"!==process.env.NODE_ENV&&function(t,e){if(!t.includes(e))throw new Error("'"+e+"' not found. It must be provided in initialState as a property key.")}(c,t);var n=e.useCallback(function(e){return e[t]},[t]);return[i(n)]},getState:function(){return i.getState()},dispatch:function(t){return i.dispatch(t)}}}}); | ||
//# sourceMappingURL=index.umd.js.map |
@@ -1,4 +0,4 @@ | ||
/// <reference types="react" /> | ||
import { SetStateAction } from 'react'; | ||
/** | ||
* create a gloal state | ||
* create a global state | ||
* | ||
@@ -20,6 +20,6 @@ * It returns a set of functions | ||
*/ | ||
export declare const createGlobalState: <State>(initialState: State) => { | ||
useGlobalState: <StateKey extends keyof State>(stateKey: StateKey) => [State[StateKey], (u: import("react").SetStateAction<State[StateKey]>) => void]; | ||
getGlobalState: <StateKey_1 extends keyof State>(key: StateKey_1) => State[StateKey_1]; | ||
setGlobalState: <StateKey_2 extends keyof State>(key: StateKey_2, update: import("react").SetStateAction<State[StateKey_2]>) => void; | ||
export declare const createGlobalState: <State extends object>(initialState: State) => { | ||
useGlobalState: <StateKey extends keyof State>(stateKey: StateKey) => readonly [State[StateKey], (u: SetStateAction<State[StateKey]>) => void]; | ||
getGlobalState: <StateKey_1 extends keyof State>(stateKey: StateKey_1) => State[StateKey_1]; | ||
setGlobalState: <StateKey_2 extends keyof State>(stateKey: StateKey_2, update: SetStateAction<State[StateKey_2]>) => void; | ||
}; |
import { Reducer } from 'react'; | ||
declare type Enhancer<Creator> = (creator: Creator) => Creator; | ||
/** | ||
@@ -24,8 +23,8 @@ * create a global store | ||
*/ | ||
export declare const createStore: <State, Action>(reducer: Reducer<State, Action>, initialState?: State, enhancer?: Enhancer<any> | undefined) => { | ||
useGlobalState: <StateKey extends keyof State>(stateKey: StateKey) => [State[StateKey], (u: import("react").SetStateAction<State[StateKey]>) => void]; | ||
export declare const createStore: <State extends object, Action extends { | ||
type: unknown; | ||
}>(reducer: Reducer<State, Action>, initialState?: State, enhancer?: any) => { | ||
useGlobalState: <StateKey extends keyof State>(stateKey: StateKey) => readonly [State[StateKey]]; | ||
getState: () => State; | ||
setState: (update: import("react").SetStateAction<State>) => void; | ||
dispatch: (action: Action) => Action; | ||
}; | ||
export {}; |
@@ -1,5 +0,2 @@ | ||
export { createAtom } from './createAtom'; | ||
export { useAtom } from './useAtom'; | ||
export { createGlobalState } from './createGlobalState'; | ||
export { createStore } from './createStore'; | ||
export { reduxDevToolsExt } from './devtools'; |
127
package.json
{ | ||
"name": "react-hooks-global-state", | ||
"description": "Simple global state for React with Hooks API", | ||
"version": "2.0.0-alpha.3", | ||
"description": "Simple global state for React with Hooks API without Context API", | ||
"version": "2.0.0-alpha.4", | ||
"publishConfig": { | ||
@@ -17,2 +17,11 @@ "tag": "next" | ||
"types": "./dist/src/index.d.ts", | ||
"exports": { | ||
"./package.json": "./package.json", | ||
".": { | ||
"types": "./dist/src/index.d.ts", | ||
"module": "./dist/index.modern.js", | ||
"import": "./dist/index.modern.mjs", | ||
"default": "./dist/index.umd.js" | ||
} | ||
}, | ||
"sideEffects": false, | ||
@@ -25,2 +34,3 @@ "files": [ | ||
"compile": "microbundle build -f modern,umd", | ||
"postcompile": "cp dist/index.modern.mjs dist/index.modern.js && cp dist/index.modern.mjs.map dist/index.modern.js.map", | ||
"test": "run-s eslint tsc-test jest e2e-test:*", | ||
@@ -30,3 +40,3 @@ "eslint": "eslint --ext .js,.ts,.tsx --ignore-pattern dist .", | ||
"tsc-test": "tsc --project . --noEmit", | ||
"apidoc": "documentation readme --section API --markdown-toc false --parse-extension ts src/*.ts", | ||
"apidoc": "documentation readme --section API --markdown-toc false --parse-extension ts src/createGlobalState.ts src/createStore.ts", | ||
"e2e-test:01_minimal": "server-test examples:01_minimal 8080 'jest --preset jest-puppeteer __tests__/e2e/01_minimal.ts'", | ||
@@ -45,16 +55,22 @@ "e2e-test:02_typescript": "server-test examples:02_typescript 8080 'jest --preset jest-puppeteer __tests__/e2e/02_typescript.ts'", | ||
"e2e-test:13_persistence": "server-test examples:13_persistence 8080 'jest --preset jest-puppeteer __tests__/e2e/13_persistence.ts'", | ||
"examples:01_minimal": "DIR=01_minimal EXT=js webpack-dev-server", | ||
"examples:02_typescript": "DIR=02_typescript webpack-dev-server", | ||
"examples:03_actions": "DIR=03_actions webpack-dev-server", | ||
"examples:04_fetch": "DIR=04_fetch webpack-dev-server", | ||
"examples:05_onmount": "DIR=05_onmount webpack-dev-server", | ||
"examples:06_reducer": "DIR=06_reducer webpack-dev-server", | ||
"examples:07_middleware": "DIR=07_middleware webpack-dev-server", | ||
"examples:08_thunk": "DIR=08_thunk webpack-dev-server", | ||
"examples:09_comparison": "DIR=09_comparison webpack-dev-server", | ||
"examples:10_immer": "DIR=10_immer webpack-dev-server", | ||
"examples:11_deep": "DIR=11_deep webpack-dev-server", | ||
"examples:12_effect": "DIR=12_effect webpack-dev-server", | ||
"examples:13_persistence": "DIR=13_persistence webpack-dev-server" | ||
"examples:01_minimal": "DIR=01_minimal EXT=js webpack-cli serve", | ||
"examples:02_typescript": "DIR=02_typescript webpack-cli serve", | ||
"examples:03_actions": "DIR=03_actions webpack-cli serve", | ||
"examples:04_fetch": "DIR=04_fetch webpack-cli serve", | ||
"examples:05_onmount": "DIR=05_onmount webpack-cli serve", | ||
"examples:06_reducer": "DIR=06_reducer webpack-cli serve", | ||
"examples:07_middleware": "DIR=07_middleware webpack-cli serve", | ||
"examples:08_thunk": "DIR=08_thunk webpack-cli serve", | ||
"examples:09_comparison": "DIR=09_comparison webpack-cli serve", | ||
"examples:10_immer": "DIR=10_immer webpack-cli serve", | ||
"examples:11_deep": "DIR=11_deep webpack-cli serve", | ||
"examples:12_effect": "DIR=12_effect webpack-cli serve", | ||
"examples:13_persistence": "DIR=13_persistence webpack-cli serve" | ||
}, | ||
"jest": { | ||
"testEnvironment": "jsdom", | ||
"transform": { | ||
"^.+\\.ts$": "ts-jest" | ||
} | ||
}, | ||
"keywords": [ | ||
@@ -69,48 +85,49 @@ "react", | ||
"license": "MIT", | ||
"dependencies": {}, | ||
"dependencies": { | ||
"zustand": "^3.5.10" | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "^7.11.0", | ||
"@pmmmwh/react-refresh-webpack-plugin": "^0.4.1", | ||
"@testing-library/react": "^10.4.7", | ||
"@types/expect-puppeteer": "^4.4.3", | ||
"@types/jest": "^26.0.8", | ||
"@types/jest-environment-puppeteer": "^4.3.2", | ||
"@types/puppeteer": "^3.0.1", | ||
"@types/react": "^16.9.44", | ||
"@types/react-dom": "^16.9.8", | ||
"@types/redux-logger": "^3.0.8", | ||
"@typescript-eslint/eslint-plugin": "^3.8.0", | ||
"@typescript-eslint/parser": "^3.8.0", | ||
"babel-loader": "^8.1.0", | ||
"documentation": "^13.0.2", | ||
"eslint": "^7.6.0", | ||
"eslint-config-airbnb": "^18.2.0", | ||
"eslint-plugin-import": "^2.22.0", | ||
"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", | ||
"immer": "^7.0.7", | ||
"jest": "^26.2.2", | ||
"jest-puppeteer": "^4.4.0", | ||
"microbundle": "^0.12.3", | ||
"@testing-library/react": "^12.0.0", | ||
"@types/expect-puppeteer": "^4.4.6", | ||
"@types/jest": "^27.0.1", | ||
"@types/jest-environment-puppeteer": "^4.4.1", | ||
"@types/puppeteer": "^5.4.4", | ||
"@types/react": "^17.0.20", | ||
"@types/react-dom": "^17.0.9", | ||
"@types/redux-logger": "^3.0.9", | ||
"@typescript-eslint/eslint-plugin": "^4.31.0", | ||
"@typescript-eslint/parser": "^4.31.0", | ||
"documentation": "^13.2.5", | ||
"eslint": "^7.32.0", | ||
"eslint-config-airbnb": "^18.2.1", | ||
"eslint-plugin-import": "^2.24.2", | ||
"eslint-plugin-jsx-a11y": "^6.4.1", | ||
"eslint-plugin-react": "^7.25.1", | ||
"eslint-plugin-react-hooks": "^4.2.0", | ||
"html-webpack-plugin": "^5.3.2", | ||
"immer": "^9.0.6", | ||
"jest": "^27.1.1", | ||
"jest-puppeteer": "^5.0.4", | ||
"microbundle": "^0.13.3", | ||
"npm-run-all": "^4.1.5", | ||
"puppeteer": "^5.2.1", | ||
"react": "experimental", | ||
"react-dom": "experimental", | ||
"react-refresh": "^0.8.3", | ||
"redux": "^4.0.5", | ||
"puppeteer": "^10.2.0", | ||
"react": "^16.13.1", | ||
"react-dom": "^17.0.2", | ||
"redux": "^4.1.1", | ||
"redux-logger": "^3.0.6", | ||
"redux-thunk": "^2.3.0", | ||
"start-server-and-test": "^1.11.2", | ||
"ts-jest": "^26.1.4", | ||
"ts-loader": "^8.0.2", | ||
"typescript": "^3.9.7", | ||
"webpack": "^4.44.1", | ||
"webpack-cli": "^3.3.12", | ||
"webpack-dev-server": "^3.11.0" | ||
"start-server-and-test": "^1.14.0", | ||
"ts-jest": "^27.0.5", | ||
"ts-loader": "^9.2.5", | ||
"typescript": "^4.4.2", | ||
"webpack": "^5.52.0", | ||
"webpack-cli": "^4.8.0", | ||
"webpack-dev-server": "^4.1.1" | ||
}, | ||
"peerDependencies": { | ||
"react": ">=16.14.0" | ||
"react": ">=16.8.0" | ||
}, | ||
"resolutions": { | ||
"@types/node": "^15" | ||
} | ||
} |
131
README.md
@@ -6,4 +6,5 @@ # react-hooks-global-state | ||
[](https://bundlephobia.com/result?p=react-hooks-global-state) | ||
[](https://discord.gg/MrQdmzd) | ||
Simple global state for React with Hooks API | ||
Simple global state for React with Hooks API without Context API | ||
@@ -15,15 +16,8 @@ ## Introduction | ||
- React Hooks only API without React Context | ||
- You don't need Context for global state. | ||
- Hardly misusable selector by state keys | ||
- For most of cases, function selectors are not necessary. | ||
- Optimization for shallow state getter and setter. | ||
- The library cares the state object only one-level deep. | ||
- TypeScript type definitions | ||
- A creator function creates hooks with types inferred. | ||
- Analogous APIs | ||
- useGlobalState works like React.useState. | ||
- useAtom resembles with the concept of Recoil. | ||
- createStore implies Redux. | ||
- Concurrent Mode support | ||
- Under the hood, it's implemented with useMutableSource. | ||
- (For external stores like this, state branching is never possible.) | ||
- Redux middleware support to some extent | ||
- Some of libraries in Redux ecosystem can be used. | ||
@@ -38,36 +32,6 @@ ## Install | ||
### createAtom style | ||
### setState style | ||
```javascript | ||
import React from 'react'; | ||
import { createAtom, useAtom } from 'react-hooks-global-state'; | ||
const initialState = { count: 0 }; | ||
const atom1 = createAtom(initialState); | ||
const Counter = () => { | ||
const [count, setCount] = useAtom(atom1, 'count'); | ||
return ( | ||
<div> | ||
<span>Counter: {count}</span> | ||
{/* update state by passing callback function */} | ||
<button onClick={() => setCount(v => v + 1)}>+1</button> | ||
{/* update state by passing new value */} | ||
<button onClick={() => setCount(count - 1)}>-1</button> | ||
</div> | ||
); | ||
}; | ||
const App = () => ( | ||
<> | ||
<Counter /> | ||
<Counter /> | ||
</> | ||
); | ||
``` | ||
### createGlobalState style | ||
```javascript | ||
import React from 'react'; | ||
import { createGlobalState } from 'react-hooks-global-state'; | ||
@@ -99,3 +63,3 @@ | ||
### createStore style | ||
### reducer style | ||
@@ -139,32 +103,5 @@ ```javascript | ||
### createAtom | ||
create an atom | ||
It returns a set of functions to be called outside React | ||
- `getStateByKey`: a function to get the part of state by key outside React | ||
- `setStateByKey`: a function to set the part of state by key outside React | ||
- `getState`: a function to get the entire state | ||
- `setState`: a function to get the entire state | ||
- `dispatch`: an optional function that can be used if reducer is provided | ||
#### Parameters | ||
- `initialState` **State** | ||
- `reducer` **Reducer<State, Action>?** | ||
#### Examples | ||
```javascript | ||
import { createAtom } from 'react-hooks-global-state'; | ||
const atom = createAtom({ count: 0 }); | ||
atom.setStateByKey('count', 1); | ||
``` | ||
### createGlobalState | ||
create a gloal state | ||
create a global state | ||
@@ -225,26 +162,2 @@ It returns a set of functions | ||
### useAtom | ||
use atom | ||
a custom hook that works like React.useState | ||
#### Parameters | ||
- `atom` **Atom<State, any>** | ||
- `stateKey` **any?** | ||
#### Examples | ||
```javascript | ||
import { createAtom, useAtom } from 'react-hooks-global-state'; | ||
const atom = createAtom({ count: 0 }); | ||
const Component = () => { | ||
const [count, setCount] = useAtom(atom, 'count'); | ||
... | ||
}; | ||
``` | ||
## Examples | ||
@@ -262,15 +175,15 @@ | ||
You can also try them in codesandbox.io: | ||
[01](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/master/examples/01_minimal) | ||
[02](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/master/examples/02_typescript) | ||
[03](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/master/examples/03_actions) | ||
[04](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/master/examples/04_fetch) | ||
[05](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/master/examples/05_onmount) | ||
[06](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/master/examples/06_reducer) | ||
[07](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/master/examples/07_middleware) | ||
[08](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/master/examples/08_thunk) | ||
[09](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/master/examples/09_comparison) | ||
[10](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/master/examples/10_immer) | ||
[11](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/master/examples/11_deep) | ||
[12](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/master/examples/12_effect) | ||
[13](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/master/examples/13_persistence) | ||
[01](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/main/examples/01_minimal) | ||
[02](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/main/examples/02_typescript) | ||
[03](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/main/examples/03_actions) | ||
[04](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/main/examples/04_fetch) | ||
[05](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/main/examples/05_onmount) | ||
[06](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/main/examples/06_reducer) | ||
[07](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/main/examples/07_middleware) | ||
[08](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/main/examples/08_thunk) | ||
[09](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/main/examples/09_comparison) | ||
[10](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/main/examples/10_immer) | ||
[11](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/main/examples/11_deep) | ||
[12](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/main/examples/12_effect) | ||
[13](https://codesandbox.io/s/github/dai-shi/react-hooks-global-state/tree/main/examples/13_persistence) | ||
@@ -277,0 +190,0 @@ ## Blogs |
@@ -1,6 +0,22 @@ | ||
import { createAtom } from './createAtom'; | ||
import { useAtom } from './useAtom'; | ||
import { SetStateAction, useCallback } from 'react'; | ||
import create from 'zustand'; | ||
const validateStateKey = (keys: string[], stateKey: string) => { | ||
if (!keys.includes(stateKey)) { | ||
throw new Error(`'${stateKey}' not found. It must be provided in initialState as a property key.`); | ||
} | ||
}; | ||
const isFunction = (fn: unknown): fn is Function => (typeof fn === 'function'); | ||
const updateValue = <Value>(oldValue: Value, newValue: SetStateAction<Value>) => { | ||
if (isFunction(newValue)) { | ||
return newValue(oldValue); | ||
} | ||
return newValue; | ||
}; | ||
/** | ||
* create a gloal state | ||
* create a global state | ||
* | ||
@@ -22,11 +38,45 @@ * It returns a set of functions | ||
*/ | ||
export const createGlobalState = <State>(initialState: State) => { | ||
const atom = createAtom(initialState); | ||
export const createGlobalState = <State extends object>(initialState: State) => { | ||
const useStore = create<State>(() => initialState); | ||
type StateKeys = keyof State; | ||
const keys = Object.keys(initialState); | ||
const setGlobalState = <StateKey extends StateKeys>( | ||
stateKey: StateKey, | ||
update: SetStateAction<State[StateKey]>, | ||
) => { | ||
if (process.env.NODE_ENV !== 'production') { | ||
validateStateKey(keys, stateKey as string); | ||
} | ||
useStore.setState((previousState) => ({ | ||
[stateKey]: updateValue(previousState[stateKey], update), | ||
} as Pick<State, StateKey>)); | ||
}; | ||
const useGlobalState = <StateKey extends StateKeys>(stateKey: StateKey) => { | ||
if (process.env.NODE_ENV !== 'production') { | ||
validateStateKey(keys, stateKey as string); | ||
} | ||
const selector = useCallback((state: State) => state[stateKey], [stateKey]); | ||
const partialState = useStore(selector); | ||
const updater = useCallback( | ||
(u: SetStateAction<State[StateKey]>) => setGlobalState(stateKey, u), | ||
[stateKey], | ||
); | ||
return [partialState, updater] as const; | ||
}; | ||
const getGlobalState = <StateKey extends StateKeys>(stateKey: StateKey) => { | ||
if (process.env.NODE_ENV !== 'production') { | ||
validateStateKey(keys, stateKey as string); | ||
} | ||
return useStore.getState()[stateKey]; | ||
}; | ||
return { | ||
useGlobalState: <StateKey extends keyof State>(stateKey: StateKey) => ( | ||
useAtom<State, StateKey>(atom, stateKey) | ||
), | ||
getGlobalState: atom.getStateByKey, | ||
setGlobalState: atom.setStateByKey, | ||
useGlobalState, | ||
getGlobalState, | ||
setGlobalState, | ||
}; | ||
}; |
/* eslint @typescript-eslint/no-explicit-any: off */ | ||
import { Reducer } from 'react'; | ||
import { Reducer, useCallback } from 'react'; | ||
import { Atom, createAtom } from './createAtom'; | ||
import { useAtom } from './useAtom'; | ||
import create from 'zustand'; | ||
import { redux } from 'zustand/middleware'; | ||
type Enhancer<Creator> = (creator: Creator) => Creator; | ||
const validateStateKey = (keys: string[], stateKey: string) => { | ||
if (!keys.includes(stateKey)) { | ||
throw new Error(`'${stateKey}' not found. It must be provided in initialState as a property key.`); | ||
} | ||
}; | ||
@@ -31,17 +35,32 @@ /** | ||
*/ | ||
export const createStore = <State, Action>( | ||
export const createStore = <State extends object, Action extends { type: unknown }>( | ||
reducer: Reducer<State, Action>, | ||
initialState: State = (reducer as any)(undefined, { type: undefined }), | ||
enhancer?: Enhancer<any>, | ||
enhancer?: any, | ||
) => { | ||
if (enhancer) return enhancer(createStore)(reducer, initialState) as never; | ||
const atom = createAtom(initialState, reducer); | ||
const useStore = create<State>(redux(reducer, initialState)); | ||
type StateKeys = keyof State; | ||
const keys = Object.keys(initialState); | ||
const useGlobalState = <StateKey extends StateKeys>(stateKey: StateKey) => { | ||
if (process.env.NODE_ENV !== 'production') { | ||
validateStateKey(keys, stateKey as string); | ||
} | ||
const selector = useCallback((state: State) => state[stateKey], [stateKey]); | ||
const partialState = useStore(selector); | ||
return [partialState] as const; | ||
}; | ||
const getState = (): State => useStore.getState(); | ||
const dispatch = (action: Action): Action => (useStore as any).dispatch(action); | ||
return { | ||
useGlobalState: <StateKey extends keyof State>(stateKey: StateKey) => ( | ||
useAtom<State, StateKey>(atom as Atom<State, any>, stateKey) | ||
), | ||
getState: atom.getState, | ||
setState: atom.setState, // for library use | ||
dispatch: atom.dispatch, | ||
useGlobalState, | ||
getState, | ||
dispatch, | ||
}; | ||
}; |
@@ -1,6 +0,2 @@ | ||
export { createAtom } from './createAtom'; | ||
export { useAtom } from './useAtom'; | ||
export { createGlobalState } from './createGlobalState'; | ||
export { createStore } from './createStore'; | ||
export { reduxDevToolsExt } from './devtools'; |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
36
45082
2
16
200
196
12
1
+ Addedzustand@^3.5.10
+ Addedzustand@3.7.2(transitive)