diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7338c8a..10630f3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,7 @@
## [Unreleased]
### Changed
-- Reduce bundle size a little
+- New API without context
## [0.17.0] - 2020-01-09
### Changed
diff --git a/README.md b/README.md
index 2707567..6ae9426 100644
--- a/README.md
+++ b/README.md
@@ -8,10 +8,8 @@ Simple global state for React with Hooks API
## Introduction
-If you ever try to implement a global state with Context and Hooks,
-you probably find it straightforward.
-This library provide more or less the same functionality
-with some following bonuses.
+This is a library to provide a global state with React Hooks.
+It has following characteristics.
- Optimization for shallow state getter and setter.
- The library cares the state object only one-level deep.
@@ -20,9 +18,8 @@ with some following bonuses.
- Redux middleware support to some extent
- Some of libraries in Redux ecosystem can be used.
- Redux DevTools Extension could be used in a simple scenario.
-
-Due to the fact that this library utilizes `unstable_observedBits`
-for optimization, this library is still in alpha.
+- Concurrent Mode support (Experimental)
+ - Undocumented `useGlobalStateProvider` supports CM without React Context.
## Install
@@ -39,7 +36,7 @@ import React from 'react';
import { createGlobalState } from 'react-hooks-global-state';
const initialState = { count: 0 };
-const { GlobalStateProvider, useGlobalState } = createGlobalState(initialState);
+const { useGlobalState } = createGlobalState(initialState);
const Counter = () => {
const [count, setCount] = useGlobalState('count');
@@ -55,10 +52,10 @@ const Counter = () => {
};
const App = () => (
-
+ <>
-
+ >
);
```
@@ -76,7 +73,7 @@ const reducer = (state, action) => {
}
};
const initialState = { count: 0 };
-const { GlobalStateProvider, dispatch, useGlobalState } = createStore(reducer, initialState);
+const { dispatch, useGlobalState } = createStore(reducer, initialState);
const Counter = () => {
const [value] = useGlobalState('count');
@@ -90,10 +87,10 @@ const Counter = () => {
};
const App = () => (
-
+ <>
-
+ >
);
```
@@ -123,12 +120,6 @@ You can also try them in codesandbox.io:
[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)
-## Limitations
-
-- Due to the implementation relying on `observedBits` in the Context API,
- the performance may drop down if a state holds more than 30 items.
- Reference: [#1](https://github.com/dai-shi/react-hooks-global-state/issues/1)
-
## Blogs
- [TypeScript-aware React hooks for global state](https://blog.axlight.com/posts/typescript-aware-react-hooks-for-global-state/)
diff --git a/__tests__/01_basic_spec.js b/__tests__/01_basic_spec.js
index 5e66918..43dcf98 100644
--- a/__tests__/01_basic_spec.js
+++ b/__tests__/01_basic_spec.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { StrictMode } from 'react';
import { render, fireEvent, cleanup } from '@testing-library/react';
import { createGlobalState, createStore } from '../src/index';
@@ -12,7 +12,7 @@ describe('basic spec', () => {
it('should be possible to not specify initial state', () => {
const reducer = () => ({ count: 0 });
- const { GlobalStateProvider, useGlobalState } = createStore(reducer);
+ const { useGlobalState } = createStore(reducer);
const Counter = () => {
const [value, update] = useGlobalState('count');
return (
@@ -23,9 +23,9 @@ describe('basic spec', () => {
);
};
const App = () => (
-
+
-
+
);
const { getByText } = render();
expect(getByText('0')).toBeDefined();
@@ -37,7 +37,7 @@ describe('basic spec', () => {
const initialState = {
count1: 0,
};
- const { GlobalStateProvider, useGlobalState } = createGlobalState(initialState);
+ const { useGlobalState } = createGlobalState(initialState);
const Counter = () => {
const [value, update] = useGlobalState('count1');
return (
@@ -48,10 +48,10 @@ describe('basic spec', () => {
);
};
const App = () => (
-
+
-
+
);
const { getAllByText, container } = render();
expect(container).toMatchSnapshot();
diff --git a/__tests__/02_useeffect_spec.js b/__tests__/02_useeffect_spec.js
index bac171b..7045023 100644
--- a/__tests__/02_useeffect_spec.js
+++ b/__tests__/02_useeffect_spec.js
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import React, { StrictMode, useEffect } from 'react';
import { render, cleanup } from '@testing-library/react';
import { createGlobalState } from '../src/index';
@@ -10,7 +10,7 @@ describe('useeffect spec', () => {
const initialState = {
count1: 0,
};
- const { GlobalStateProvider, useGlobalState } = createGlobalState(initialState);
+ const { useGlobalState } = createGlobalState(initialState);
const Counter = () => {
const [value, update] = useGlobalState('count1');
useEffect(() => {
@@ -23,9 +23,9 @@ describe('useeffect spec', () => {
);
};
const App = () => (
-
+
-
+
);
const { container } = render();
expect(container).toMatchSnapshot();
diff --git a/__tests__/03_startup_spec.js b/__tests__/03_startup_spec.js
index 1889e6f..b2a0bd1 100644
--- a/__tests__/03_startup_spec.js
+++ b/__tests__/03_startup_spec.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { StrictMode } from 'react';
import { render, cleanup } from '@testing-library/react';
import { createGlobalState, createStore } from '../src/index';
@@ -11,7 +11,7 @@ describe('startup spec', () => {
count1: 0,
count2: 0,
};
- const { GlobalStateProvider, setGlobalState, useGlobalState } = createGlobalState(initialState);
+ const { setGlobalState, useGlobalState } = createGlobalState(initialState);
const Counter = ({ name }) => {
setGlobalState(name, 9);
const [value] = useGlobalState(name);
@@ -23,10 +23,10 @@ describe('startup spec', () => {
);
};
const App = () => (
-
+
-
+
);
const { getByTestId } = render();
expect(getByTestId('count1').innerHTML).toBe('9');
@@ -47,11 +47,7 @@ describe('startup spec', () => {
}
return state;
};
- const {
- GlobalStateProvider,
- dispatch,
- useGlobalState,
- } = createStore(reducer, initialState);
+ const { dispatch, useGlobalState } = createStore(reducer, initialState);
const Counter = ({ name }) => {
dispatch({ type: 'setCounter', name, value: 9 });
const [value] = useGlobalState(name);
@@ -63,10 +59,10 @@ describe('startup spec', () => {
);
};
const App = () => (
-
+
-
+
);
const { getByTestId } = render();
expect(getByTestId('count1').innerHTML).toBe('9');
diff --git a/dist/index.d.ts b/dist/index.d.ts
index 81641fd..736b351 100644
--- a/dist/index.d.ts
+++ b/dist/index.d.ts
@@ -1,10 +1,12 @@
-import { ComponentType, SetStateAction, Reducer } from 'react';
+import { SetStateAction, Reducer } from 'react';
type SetGlobalState = (
name: N,
setStateAction: SetStateAction,
) => void;
+type UseGlobalStateProvider = () => void;
+
type UseGlobalState = (name: N) => [
S[N],
(setStateAction: SetStateAction) => void,
@@ -13,7 +15,7 @@ type UseGlobalState = (name: N) => [
export type Dispatch = (action: A) => A;
export type Store = {
- GlobalStateProvider: ComponentType;
+ useGlobalStateProvider: UseGlobalStateProvider;
useGlobalState: UseGlobalState;
getState: () => S;
dispatch: Dispatch;
@@ -26,7 +28,7 @@ export type Enhancer = (creator: StoreCreator) => StoreCreator
type AnyEnhancer = unknown;
export type CreateGlobalState = (initialState: S) => {
- GlobalStateProvider: ComponentType;
+ useGlobalStateProvider: UseGlobalStateProvider;
useGlobalState: UseGlobalState;
setGlobalState: SetGlobalState;
getGlobalState: (name: N) => S[N];
diff --git a/dist/index.js b/dist/index.js
index d6eba8b..2ce688e 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -7,12 +7,6 @@ exports.createStore = exports.createGlobalState = void 0;
var _react = require("react");
-function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
-
-function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
-
-function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
-
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
@@ -21,6 +15,12 @@ function _iterableToArrayLimit(arr, i) { if (!(Symbol.iterator in Object(arr) ||
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
+function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
+
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
// utility functions
var isFunction = function isFunction(fn) {
return typeof fn === 'function';
@@ -32,24 +32,15 @@ var updateValue = function updateValue(oldValue, newValue) {
}
return newValue;
-}; // ref: https://github.com/dai-shi/react-hooks-global-state/issues/5
-
-
-var useUnstableContextWithoutWarning = function useUnstableContextWithoutWarning(Context, observedBits) {
- var ReactCurrentDispatcher = _react.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentDispatcher;
- var dispatcher = ReactCurrentDispatcher.current;
-
- if (!dispatcher) {
- throw new Error('Hooks can only be called inside the body of a function component. (https://fb.me/react-invalid-hook-call)');
- }
-
- return dispatcher.useContext(Context, observedBits);
}; // core functions
-var EMPTY_OBJECT = {};
-var UPDATE_STATE = Symbol('UPDATE_STATE');
-var PROP_GLOBAL_STATE_PROVIDER = 'p';
+var UPDATE_STATE = process.env.NODE_ENV !== 'production' ? Symbol('UPDATE_STATE')
+/* for production */
+: Symbol();
+var PROP_UPDATER = 'r';
+var PROP_STATE = 'e';
+var PROP_USE_GLOBAL_STATE_PROVIDER = 'p';
var PROP_SET_GLOBAL_STATE = 's';
var PROP_USE_GLOBAL_STATE = 'u';
var PROP_GET_GLOBAL_STATE = 'g';
@@ -58,71 +49,24 @@ var PROP_SET_WHOLE_STATE = 'i';
var PROP_DISPATCH_ACTION = 'd';
var createGlobalStateCommon = function createGlobalStateCommon(reducer, initialState) {
- var _ref2;
+ var _ref;
var keys = Object.keys(initialState);
- var wholeState = initialState;
- var listener = null;
+ var globalState = initialState;
+ var linkedDispatch = null;
+ var listeners = {};
+ keys.forEach(function (key) {
+ listeners[key] = new Set();
+ });
var patchedReducer = function patchedReducer(state, action) {
if (action.type === UPDATE_STATE) {
- return action.updater(state);
+ return action[PROP_UPDATER] ? action[PROP_UPDATER](state) : action[PROP_STATE];
}
return reducer(state, action);
};
- var calculateChangedBits = function calculateChangedBits(a, b) {
- var bits = 0;
- keys.forEach(function (k, i) {
- if (a[k] !== b[k]) bits |= 1 << i;
- });
- return bits;
- };
-
- var Context = (0, _react.createContext)(EMPTY_OBJECT, calculateChangedBits);
-
- var GlobalStateProvider = function GlobalStateProvider(_ref) {
- var children = _ref.children;
-
- var _useReducer = (0, _react.useReducer)(patchedReducer, initialState),
- _useReducer2 = _slicedToArray(_useReducer, 2),
- state = _useReducer2[0],
- dispatch = _useReducer2[1];
-
- (0, _react.useEffect)(function () {
- if (listener) throw new Error('You cannot use more than once.');
- listener = dispatch;
-
- if (state !== initialState) {
- // probably state was saved by react-hot-loader, so restore it
- wholeState = state;
- } else if (state !== wholeState) {
- // wholeState was updated during initialization
- dispatch({
- type: UPDATE_STATE,
- updater: function updater() {
- return wholeState;
- }
- });
- }
-
- var cleanup = function cleanup() {
- listener = null;
- };
-
- return cleanup; // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [initialState]); // trick for react-hot-loader
-
- (0, _react.useEffect)(function () {
- // store the latest state
- wholeState = state;
- });
- return (0, _react.createElement)(Context.Provider, {
- value: state
- }, children);
- };
-
var validateName = function validateName(name) {
if (!keys.includes(name)) {
throw new Error("'".concat(name, "' not found. It must be provided in initialState as a property key."));
@@ -138,29 +82,83 @@ var createGlobalStateCommon = function createGlobalStateCommon(reducer, initialS
return _objectSpread({}, previousState, _defineProperty({}, name, updateValue(previousState[name], update)));
};
- if (listener) {
- listener({
- type: UPDATE_STATE,
- updater: updater
- });
+ if (linkedDispatch) {
+ linkedDispatch(_defineProperty({
+ type: UPDATE_STATE
+ }, PROP_UPDATER, updater));
} else {
- wholeState = updater(wholeState);
+ globalState = updater(globalState);
+ var nextPartialState = globalState[name];
+ listeners[name].forEach(function (listener) {
+ return listener(nextPartialState);
+ });
}
};
+ var notifyListeners = function notifyListeners(prevState, nextState) {
+ keys.forEach(function (key) {
+ var nextPartialState = nextState[key];
+
+ if (prevState[key] !== nextPartialState) {
+ listeners[key].forEach(function (listener) {
+ return listener(nextPartialState);
+ });
+ }
+ });
+ };
+
+ var useGlobalStateProvider = function useGlobalStateProvider() {
+ var _useReducer = (0, _react.useReducer)(patchedReducer, globalState),
+ _useReducer2 = _slicedToArray(_useReducer, 2),
+ state = _useReducer2[0],
+ dispatch = _useReducer2[1];
+
+ (0, _react.useEffect)(function () {
+ if (linkedDispatch) throw new Error('Only one global state provider is allowed');
+ linkedDispatch = dispatch; // in case it's changed before this effect is handled
+
+ dispatch(_defineProperty({
+ type: UPDATE_STATE
+ }, PROP_STATE, globalState));
+
+ var cleanup = function cleanup() {
+ linkedDispatch = null;
+ };
+
+ return cleanup;
+ }, []);
+ var prevGlobalState = (0, _react.useRef)(state);
+ notifyListeners(prevGlobalState.current, state);
+ prevGlobalState.current = state;
+ (0, _react.useEffect)(function () {
+ globalState = state;
+ }, [state]);
+ };
+
var useGlobalState = function useGlobalState(name) {
if (process.env.NODE_ENV !== 'production') {
validateName(name);
}
- var index = keys.indexOf(name);
- var observedBits = 1 << index;
- var state = useUnstableContextWithoutWarning(Context, observedBits);
- if (state === EMPTY_OBJECT) throw new Error('Please use ');
+ var _useState = (0, _react.useState)(globalState[name]),
+ _useState2 = _slicedToArray(_useState, 2),
+ partialState = _useState2[0],
+ setPartialState = _useState2[1];
+
+ (0, _react.useEffect)(function () {
+ listeners[name].add(setPartialState);
+ setPartialState(globalState[name]); // in case it's changed before this effect is handled
+
+ var cleanup = function cleanup() {
+ listeners[name]["delete"](setPartialState);
+ };
+
+ return cleanup;
+ }, [name]);
var updater = (0, _react.useCallback)(function (u) {
return setGlobalState(name, u);
}, [name]);
- return [state[name], updater];
+ return [partialState, updater];
};
var getGlobalState = function getGlobalState(name) {
@@ -168,37 +166,38 @@ var createGlobalStateCommon = function createGlobalStateCommon(reducer, initialS
validateName(name);
}
- return wholeState[name];
+ return globalState[name];
};
var getWholeState = function getWholeState() {
- return wholeState;
+ return globalState;
};
- var setWholeState = function setWholeState(state) {
- if (listener) {
- listener({
- type: UPDATE_STATE,
- updater: function updater() {
- return state;
- }
- });
+ var setWholeState = function setWholeState(nextGlobalState) {
+ if (linkedDispatch) {
+ linkedDispatch(_defineProperty({
+ type: UPDATE_STATE
+ }, PROP_STATE, nextGlobalState));
} else {
- wholeState = state;
+ var prevGlobalState = globalState;
+ globalState = nextGlobalState;
+ notifyListeners(prevGlobalState, globalState);
}
};
var dispatchAction = function dispatchAction(action) {
- if (listener) {
- listener(action);
+ if (linkedDispatch) {
+ linkedDispatch(action);
} else {
- wholeState = reducer(wholeState, action);
+ var prevGlobalState = globalState;
+ globalState = reducer(globalState, action);
+ notifyListeners(prevGlobalState, globalState);
}
return action;
};
- return _ref2 = {}, _defineProperty(_ref2, PROP_GLOBAL_STATE_PROVIDER, GlobalStateProvider), _defineProperty(_ref2, PROP_SET_GLOBAL_STATE, setGlobalState), _defineProperty(_ref2, PROP_USE_GLOBAL_STATE, useGlobalState), _defineProperty(_ref2, PROP_GET_GLOBAL_STATE, getGlobalState), _defineProperty(_ref2, PROP_GET_WHOLE_STATE, getWholeState), _defineProperty(_ref2, PROP_SET_WHOLE_STATE, setWholeState), _defineProperty(_ref2, PROP_DISPATCH_ACTION, dispatchAction), _ref2;
+ return _ref = {}, _defineProperty(_ref, PROP_USE_GLOBAL_STATE_PROVIDER, useGlobalStateProvider), _defineProperty(_ref, PROP_SET_GLOBAL_STATE, setGlobalState), _defineProperty(_ref, PROP_USE_GLOBAL_STATE, useGlobalState), _defineProperty(_ref, PROP_GET_GLOBAL_STATE, getGlobalState), _defineProperty(_ref, PROP_GET_WHOLE_STATE, getWholeState), _defineProperty(_ref, PROP_SET_WHOLE_STATE, setWholeState), _defineProperty(_ref, PROP_DISPATCH_ACTION, dispatchAction), _ref;
}; // export functions
@@ -206,13 +205,13 @@ var createGlobalState = function createGlobalState(initialState) {
var _createGlobalStateCom = createGlobalStateCommon(function (state) {
return state;
}, initialState),
- GlobalStateProvider = _createGlobalStateCom[PROP_GLOBAL_STATE_PROVIDER],
+ useGlobalStateProvider = _createGlobalStateCom[PROP_USE_GLOBAL_STATE_PROVIDER],
useGlobalState = _createGlobalStateCom[PROP_USE_GLOBAL_STATE],
setGlobalState = _createGlobalStateCom[PROP_SET_GLOBAL_STATE],
getGlobalState = _createGlobalStateCom[PROP_GET_GLOBAL_STATE];
return {
- GlobalStateProvider: GlobalStateProvider,
+ useGlobalStateProvider: useGlobalStateProvider,
useGlobalState: useGlobalState,
setGlobalState: setGlobalState,
getGlobalState: getGlobalState
@@ -228,14 +227,14 @@ var createStore = function createStore(reducer, initialState, enhancer) {
if (enhancer) return enhancer(createStore)(reducer, initialState);
var _createGlobalStateCom2 = createGlobalStateCommon(reducer, initialState),
- GlobalStateProvider = _createGlobalStateCom2[PROP_GLOBAL_STATE_PROVIDER],
+ useGlobalStateProvider = _createGlobalStateCom2[PROP_USE_GLOBAL_STATE_PROVIDER],
useGlobalState = _createGlobalStateCom2[PROP_USE_GLOBAL_STATE],
getWholeState = _createGlobalStateCom2[PROP_GET_WHOLE_STATE],
setWholeState = _createGlobalStateCom2[PROP_SET_WHOLE_STATE],
dispatchAction = _createGlobalStateCom2[PROP_DISPATCH_ACTION];
return {
- GlobalStateProvider: GlobalStateProvider,
+ useGlobalStateProvider: useGlobalStateProvider,
useGlobalState: useGlobalState,
getState: getWholeState,
setState: setWholeState,
diff --git a/examples/01_minimal/src/index.js b/examples/01_minimal/src/index.js
index 59d85ab..829353e 100644
--- a/examples/01_minimal/src/index.js
+++ b/examples/01_minimal/src/index.js
@@ -7,7 +7,7 @@ const initialState = {
count: 0,
text: 'hello',
};
-const { GlobalStateProvider, useGlobalState } = createGlobalState(initialState);
+const { useGlobalState } = createGlobalState(initialState);
const Counter = () => {
const [value, update] = useGlobalState('count');
@@ -32,14 +32,12 @@ const TextBox = () => {
const App = () => (
-
- Counter
-
-
- TextBox
-
-
-
+ Counter
+
+
+ TextBox
+
+
);
diff --git a/examples/02_typescript/src/App.tsx b/examples/02_typescript/src/App.tsx
index 9209fcd..3dfeda3 100644
--- a/examples/02_typescript/src/App.tsx
+++ b/examples/02_typescript/src/App.tsx
@@ -1,20 +1,16 @@
import React, { StrictMode } from 'react';
-import { GlobalStateProvider } from './state';
-
import Counter from './Counter';
import Person from './Person';
const App = () => (
-
- Counter
-
-
- Person
-
-
-
+ Counter
+
+
+ Person
+
+
);
diff --git a/examples/02_typescript/src/state.ts b/examples/02_typescript/src/state.ts
index b1df74f..bc098ce 100644
--- a/examples/02_typescript/src/state.ts
+++ b/examples/02_typescript/src/state.ts
@@ -1,6 +1,6 @@
import { createGlobalState } from 'react-hooks-global-state';
-export const { GlobalStateProvider, useGlobalState } = createGlobalState({
+export const { useGlobalState } = createGlobalState({
count: 0,
person: {
age: 0,
diff --git a/examples/03_actions/src/App.tsx b/examples/03_actions/src/App.tsx
index 9209fcd..3dfeda3 100644
--- a/examples/03_actions/src/App.tsx
+++ b/examples/03_actions/src/App.tsx
@@ -1,20 +1,16 @@
import React, { StrictMode } from 'react';
-import { GlobalStateProvider } from './state';
-
import Counter from './Counter';
import Person from './Person';
const App = () => (
-
- Counter
-
-
- Person
-
-
-
+ Counter
+
+
+ Person
+
+
);
diff --git a/examples/03_actions/src/state.ts b/examples/03_actions/src/state.ts
index 0d39f25..f1748e1 100644
--- a/examples/03_actions/src/state.ts
+++ b/examples/03_actions/src/state.ts
@@ -1,6 +1,6 @@
import { createGlobalState } from 'react-hooks-global-state';
-const { GlobalStateProvider, setGlobalState, useGlobalState } = createGlobalState({
+const { setGlobalState, useGlobalState } = createGlobalState({
count: 0,
person: {
age: 0,
@@ -29,4 +29,4 @@ export const setPersonAge = (age: number) => {
setGlobalState('person', (v) => ({ ...v, age }));
};
-export { GlobalStateProvider, useGlobalState };
+export { useGlobalState };
diff --git a/examples/04_fetch/src/App.tsx b/examples/04_fetch/src/App.tsx
index b7a904b..8ba0da9 100644
--- a/examples/04_fetch/src/App.tsx
+++ b/examples/04_fetch/src/App.tsx
@@ -1,18 +1,14 @@
import React, { StrictMode } from 'react';
-import { GlobalStateProvider } from './state';
-
import ErrorMessage from './ErrorMessage';
import PageInfo from './PageInfo';
import RandomButton from './RandomButton';
const App = () => (
-
-
-
-
-
+
+
+
);
diff --git a/examples/04_fetch/src/state.ts b/examples/04_fetch/src/state.ts
index 7806678..fbe47b6 100644
--- a/examples/04_fetch/src/state.ts
+++ b/examples/04_fetch/src/state.ts
@@ -1,6 +1,6 @@
import { createGlobalState } from 'react-hooks-global-state';
-const { GlobalStateProvider, setGlobalState, useGlobalState } = createGlobalState({
+const { setGlobalState, useGlobalState } = createGlobalState({
errorMessage: '',
pageTitle: '',
});
@@ -13,4 +13,4 @@ export const setPageTitle = (s: string) => {
setGlobalState('pageTitle', s);
};
-export { GlobalStateProvider, useGlobalState };
+export { useGlobalState };
diff --git a/examples/05_onmount/src/App.tsx b/examples/05_onmount/src/App.tsx
index e7b8351..c90d874 100644
--- a/examples/05_onmount/src/App.tsx
+++ b/examples/05_onmount/src/App.tsx
@@ -1,6 +1,6 @@
import React, { useEffect, StrictMode } from 'react';
-import { GlobalStateProvider, setPageTitle } from './state';
+import { setPageTitle } from './state';
import ErrorMessage from './ErrorMessage';
import PageInfo from './PageInfo';
@@ -23,11 +23,9 @@ const App = () => {
return (
-
-
-
-
-
+
+
+
);
};
diff --git a/examples/05_onmount/src/state.ts b/examples/05_onmount/src/state.ts
index 7806678..fbe47b6 100644
--- a/examples/05_onmount/src/state.ts
+++ b/examples/05_onmount/src/state.ts
@@ -1,6 +1,6 @@
import { createGlobalState } from 'react-hooks-global-state';
-const { GlobalStateProvider, setGlobalState, useGlobalState } = createGlobalState({
+const { setGlobalState, useGlobalState } = createGlobalState({
errorMessage: '',
pageTitle: '',
});
@@ -13,4 +13,4 @@ export const setPageTitle = (s: string) => {
setGlobalState('pageTitle', s);
};
-export { GlobalStateProvider, useGlobalState };
+export { useGlobalState };
diff --git a/examples/06_reducer/src/App.tsx b/examples/06_reducer/src/App.tsx
index 9209fcd..3dfeda3 100644
--- a/examples/06_reducer/src/App.tsx
+++ b/examples/06_reducer/src/App.tsx
@@ -1,20 +1,16 @@
import React, { StrictMode } from 'react';
-import { GlobalStateProvider } from './state';
-
import Counter from './Counter';
import Person from './Person';
const App = () => (
-
- Counter
-
-
- Person
-
-
-
+ Counter
+
+
+ Person
+
+
);
diff --git a/examples/06_reducer/src/state.ts b/examples/06_reducer/src/state.ts
index ac9c037..56bed8e 100644
--- a/examples/06_reducer/src/state.ts
+++ b/examples/06_reducer/src/state.ts
@@ -7,7 +7,7 @@ type Action =
| { type: 'setLastName'; lastName: string }
| { type: 'setAge'; age: number };
-export const { GlobalStateProvider, dispatch, useGlobalState } = createStore(
+export const { dispatch, useGlobalState } = createStore(
(state, action: Action) => {
switch (action.type) {
case 'increment': return {
diff --git a/examples/07_middleware/src/App.tsx b/examples/07_middleware/src/App.tsx
index 9209fcd..3dfeda3 100644
--- a/examples/07_middleware/src/App.tsx
+++ b/examples/07_middleware/src/App.tsx
@@ -1,20 +1,16 @@
import React, { StrictMode } from 'react';
-import { GlobalStateProvider } from './state';
-
import Counter from './Counter';
import Person from './Person';
const App = () => (
-
- Counter
-
-
- Person
-
-
-
+ Counter
+
+
+ Person
+
+
);
diff --git a/examples/07_middleware/src/state.ts b/examples/07_middleware/src/state.ts
index a474c4f..2fb0a7b 100644
--- a/examples/07_middleware/src/state.ts
+++ b/examples/07_middleware/src/state.ts
@@ -62,7 +62,7 @@ const logger = (
return returnValue;
};
-export const { GlobalStateProvider, dispatch, useGlobalState } = createStore(
+export const { dispatch, useGlobalState } = createStore(
reducer,
initialState,
applyMiddleware(logger),
diff --git a/examples/08_thunk/src/App.tsx b/examples/08_thunk/src/App.tsx
index 9209fcd..3dfeda3 100644
--- a/examples/08_thunk/src/App.tsx
+++ b/examples/08_thunk/src/App.tsx
@@ -1,20 +1,16 @@
import React, { StrictMode } from 'react';
-import { GlobalStateProvider } from './state';
-
import Counter from './Counter';
import Person from './Person';
const App = () => (
-
- Counter
-
-
- Person
-
-
-
+ Counter
+
+
+ Person
+
+
);
diff --git a/examples/08_thunk/src/state.ts b/examples/08_thunk/src/state.ts
index 8b11238..772aeb9 100644
--- a/examples/08_thunk/src/state.ts
+++ b/examples/08_thunk/src/state.ts
@@ -52,7 +52,7 @@ const reducer = combineReducers({
person: personReducer,
});
-export const { GlobalStateProvider, dispatch, useGlobalState } = createStore<
+export const { dispatch, useGlobalState } = createStore<
typeof initialState,
Action
>(
diff --git a/examples/09_comparison/src/App.tsx b/examples/09_comparison/src/App.tsx
index a5f64ba..09a5cd4 100644
--- a/examples/09_comparison/src/App.tsx
+++ b/examples/09_comparison/src/App.tsx
@@ -2,7 +2,6 @@ import React, { StrictMode } from 'react';
import Counter from './Counter';
import Person from './Person';
-import { GlobalStateProvider } from './state';
import Counter2 from './Counter2';
import Person2 from './Person2';
@@ -24,14 +23,12 @@ const App = () => (
react-hooks-global-state
-
- Counter
-
-
- Person
-
-
-
+
Counter
+
+
+
Person
+
+
diff --git a/examples/09_comparison/src/state.ts b/examples/09_comparison/src/state.ts
index 5b452ee..c41b0a9 100644
--- a/examples/09_comparison/src/state.ts
+++ b/examples/09_comparison/src/state.ts
@@ -2,4 +2,4 @@ import { createStore } from 'react-hooks-global-state';
import { initialState, reducer } from './common';
-export const { GlobalStateProvider, dispatch, useGlobalState } = createStore(reducer, initialState);
+export const { dispatch, useGlobalState } = createStore(reducer, initialState);
diff --git a/examples/10_immer/src/App.tsx b/examples/10_immer/src/App.tsx
index 9209fcd..3dfeda3 100644
--- a/examples/10_immer/src/App.tsx
+++ b/examples/10_immer/src/App.tsx
@@ -1,20 +1,16 @@
import React, { StrictMode } from 'react';
-import { GlobalStateProvider } from './state';
-
import Counter from './Counter';
import Person from './Person';
const App = () => (
-
- Counter
-
-
- Person
-
-
-
+ Counter
+
+
+ Person
+
+
);
diff --git a/examples/10_immer/src/state.ts b/examples/10_immer/src/state.ts
index 156adf9..4e50d41 100644
--- a/examples/10_immer/src/state.ts
+++ b/examples/10_immer/src/state.ts
@@ -9,7 +9,7 @@ type Action =
| { type: 'setLastName'; lastName: string }
| { type: 'setAge'; age: number };
-export const { GlobalStateProvider, dispatch, useGlobalState } = createStore(
+export const { dispatch, useGlobalState } = createStore(
(state, action: Action) => produce(state, (draft) => {
switch (action.type) {
case 'increment': draft.count += 1; break;
diff --git a/examples/11_deep/src/App.tsx b/examples/11_deep/src/App.tsx
index 9209fcd..3dfeda3 100644
--- a/examples/11_deep/src/App.tsx
+++ b/examples/11_deep/src/App.tsx
@@ -1,20 +1,16 @@
import React, { StrictMode } from 'react';
-import { GlobalStateProvider } from './state';
-
import Counter from './Counter';
import Person from './Person';
const App = () => (
-
- Counter
-
-
- Person
-
-
-
+ Counter
+
+
+ Person
+
+
);
diff --git a/examples/11_deep/src/state.ts b/examples/11_deep/src/state.ts
index ac9c037..56bed8e 100644
--- a/examples/11_deep/src/state.ts
+++ b/examples/11_deep/src/state.ts
@@ -7,7 +7,7 @@ type Action =
| { type: 'setLastName'; lastName: string }
| { type: 'setAge'; age: number };
-export const { GlobalStateProvider, dispatch, useGlobalState } = createStore(
+export const { dispatch, useGlobalState } = createStore(
(state, action: Action) => {
switch (action.type) {
case 'increment': return {
diff --git a/examples/12_effect/src/App.tsx b/examples/12_effect/src/App.tsx
index 8a8f2de..12589f5 100644
--- a/examples/12_effect/src/App.tsx
+++ b/examples/12_effect/src/App.tsx
@@ -1,16 +1,12 @@
import React, { StrictMode } from 'react';
-import { GlobalStateProvider } from './state';
-
import Counter from './Counter';
const App = () => (
-
- Counter
-
-
-
+ Counter
+
+
);
diff --git a/examples/12_effect/src/state.ts b/examples/12_effect/src/state.ts
index e6e402c..46c10d5 100644
--- a/examples/12_effect/src/state.ts
+++ b/examples/12_effect/src/state.ts
@@ -5,7 +5,7 @@ type Action =
| { type: 'decrement' }
| { type: 'addBonus'; value: number };
-export const { GlobalStateProvider, dispatch, useGlobalState } = createStore(
+export const { dispatch, useGlobalState } = createStore(
(state, action: Action) => {
switch (action.type) {
case 'increment': return {
diff --git a/examples/13_persistence/src/App.tsx b/examples/13_persistence/src/App.tsx
index ef27cfd..12f0f00 100644
--- a/examples/13_persistence/src/App.tsx
+++ b/examples/13_persistence/src/App.tsx
@@ -1,20 +1,16 @@
import React from 'react';
-import { GlobalStateProvider } from './state';
-
import Counter from './Counter';
import Person from './Person';
const App = () => (
-
- Counter
-
-
- Person
-
-
-
+ Counter
+
+
+ Person
+
+
);
diff --git a/examples/13_persistence/src/state.ts b/examples/13_persistence/src/state.ts
index a63100e..88d1de8 100644
--- a/examples/13_persistence/src/state.ts
+++ b/examples/13_persistence/src/state.ts
@@ -103,7 +103,7 @@ const saveStateToStorage = (
return returnValue;
};
-export const { GlobalStateProvider, dispatch, useGlobalState } = createStore(
+export const { dispatch, useGlobalState } = createStore(
reducer,
initialState,
applyMiddleware(saveStateToStorage),
diff --git a/examples/14_hotloader/src/App.tsx b/examples/14_hotloader/src/App.tsx
index 49fc095..06a95db 100644
--- a/examples/14_hotloader/src/App.tsx
+++ b/examples/14_hotloader/src/App.tsx
@@ -1,21 +1,17 @@
import React, { StrictMode } from 'react';
import { hot } from 'react-hot-loader/root';
-import { GlobalStateProvider } from './state';
-
import Counter from './Counter';
import Person from './Person';
const App = () => (
-
- Counter
-
-
- Person
-
-
-
+ Counter
+
+
+ Person
+
+
);
diff --git a/examples/14_hotloader/src/state.ts b/examples/14_hotloader/src/state.ts
index b1df74f..bc098ce 100644
--- a/examples/14_hotloader/src/state.ts
+++ b/examples/14_hotloader/src/state.ts
@@ -1,6 +1,6 @@
import { createGlobalState } from 'react-hooks-global-state';
-export const { GlobalStateProvider, useGlobalState } = createGlobalState({
+export const { useGlobalState } = createGlobalState({
count: 0,
person: {
age: 0,
diff --git a/package-lock.json b/package-lock.json
index 4fac38f..30e2fe9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "react-hooks-global-state",
- "version": "0.17.0",
+ "version": "1.0.0-alpha.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 7490fe8..486694d 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "react-hooks-global-state",
"description": "Simple global state for React with Hooks API",
- "version": "0.17.0",
+ "version": "1.0.0-alpha.1",
"author": "Daishi Kato",
"repository": {
"type": "git",
diff --git a/src/index.d.ts b/src/index.d.ts
index 81641fd..736b351 100644
--- a/src/index.d.ts
+++ b/src/index.d.ts
@@ -1,10 +1,12 @@
-import { ComponentType, SetStateAction, Reducer } from 'react';
+import { SetStateAction, Reducer } from 'react';
type SetGlobalState = (
name: N,
setStateAction: SetStateAction,
) => void;
+type UseGlobalStateProvider = () => void;
+
type UseGlobalState = (name: N) => [
S[N],
(setStateAction: SetStateAction) => void,
@@ -13,7 +15,7 @@ type UseGlobalState = (name: N) => [
export type Dispatch = (action: A) => A;
export type Store = {
- GlobalStateProvider: ComponentType;
+ useGlobalStateProvider: UseGlobalStateProvider;
useGlobalState: UseGlobalState;
getState: () => S;
dispatch: Dispatch;
@@ -26,7 +28,7 @@ export type Enhancer = (creator: StoreCreator) => StoreCreator
type AnyEnhancer = unknown;
export type CreateGlobalState = (initialState: S) => {
- GlobalStateProvider: ComponentType;
+ useGlobalStateProvider: UseGlobalStateProvider;
useGlobalState: UseGlobalState;
setGlobalState: SetGlobalState;
getGlobalState: (name: N) => S[N];
diff --git a/src/index.js b/src/index.js
index 3322969..f6ed6f9 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,10 +1,9 @@
import {
- createContext,
- createElement,
useCallback,
useEffect,
+ useRef,
useReducer,
- __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
+ useState,
} from 'react';
// utility functions
@@ -18,20 +17,8 @@ const updateValue = (oldValue, newValue) => {
return newValue;
};
-// ref: https://github.com/dai-shi/react-hooks-global-state/issues/5
-const useUnstableContextWithoutWarning = (Context, observedBits) => {
- const { ReactCurrentDispatcher } = __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
- const dispatcher = ReactCurrentDispatcher.current;
- if (!dispatcher) {
- throw new Error('Hooks can only be called inside the body of a function component. (https://fb.me/react-invalid-hook-call)');
- }
- return dispatcher.useContext(Context, observedBits);
-};
-
// core functions
-const EMPTY_OBJECT = {};
-
const UPDATE_STATE = (
process.env.NODE_ENV !== 'production' ? Symbol('UPDATE_STATE')
/* for production */ : Symbol()
@@ -40,7 +27,7 @@ const UPDATE_STATE = (
const PROP_UPDATER = 'r';
const PROP_STATE = 'e';
-const PROP_GLOBAL_STATE_PROVIDER = 'p';
+const PROP_USE_GLOBAL_STATE_PROVIDER = 'p';
const PROP_SET_GLOBAL_STATE = 's';
const PROP_USE_GLOBAL_STATE = 'u';
const PROP_GET_GLOBAL_STATE = 'g';
@@ -50,8 +37,12 @@ const PROP_DISPATCH_ACTION = 'd';
const createGlobalStateCommon = (reducer, initialState) => {
const keys = Object.keys(initialState);
- let wholeState = initialState;
- let listener = null;
+ let globalState = initialState;
+ let linkedDispatch = null;
+ const listeners = {};
+ keys.forEach((key) => {
+ listeners[key] = new Set();
+ });
const patchedReducer = (state, action) => {
if (action.type === UPDATE_STATE) {
@@ -60,41 +51,6 @@ const createGlobalStateCommon = (reducer, initialState) => {
return reducer(state, action);
};
- const calculateChangedBits = (a, b) => {
- let bits = 0;
- keys.forEach((k, i) => {
- if (a[k] !== b[k]) bits |= 1 << i;
- });
- return bits;
- };
-
- const Context = createContext(EMPTY_OBJECT, calculateChangedBits);
-
- const GlobalStateProvider = ({ children }) => {
- const [state, dispatch] = useReducer(patchedReducer, initialState);
- useEffect(() => {
- if (listener) throw new Error('You cannot use more than once.');
- listener = dispatch;
- if (state !== initialState) {
- // probably state was saved by react-hot-loader, so restore it
- wholeState = state;
- } else if (state !== wholeState) {
- // wholeState was updated during initialization
- dispatch({ type: UPDATE_STATE, [PROP_STATE]: wholeState });
- }
- const cleanup = () => {
- listener = null;
- };
- return cleanup;
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [initialState]); // trick for react-hot-loader
- useEffect(() => {
- // store the latest state
- wholeState = state;
- });
- return createElement(Context.Provider, { value: state }, children);
- };
-
const validateName = (name) => {
if (!keys.includes(name)) {
throw new Error(`'${name}' not found. It must be provided in initialState as a property key.`);
@@ -109,53 +65,93 @@ const createGlobalStateCommon = (reducer, initialState) => {
...previousState,
[name]: updateValue(previousState[name], update),
});
- if (listener) {
- listener({ type: UPDATE_STATE, [PROP_UPDATER]: updater });
+ if (linkedDispatch) {
+ linkedDispatch({ type: UPDATE_STATE, [PROP_UPDATER]: updater });
} else {
- wholeState = updater(wholeState);
+ globalState = updater(globalState);
+ const nextPartialState = globalState[name];
+ listeners[name].forEach((listener) => listener(nextPartialState));
}
};
+ const notifyListeners = (prevState, nextState) => {
+ keys.forEach((key) => {
+ const nextPartialState = nextState[key];
+ if (prevState[key] !== nextPartialState) {
+ listeners[key].forEach((listener) => listener(nextPartialState));
+ }
+ });
+ };
+
+ const useGlobalStateProvider = () => {
+ const [state, dispatch] = useReducer(patchedReducer, globalState);
+ useEffect(() => {
+ if (linkedDispatch) throw new Error('Only one global state provider is allowed');
+ linkedDispatch = dispatch;
+ // in case it's changed before this effect is handled
+ dispatch({ type: UPDATE_STATE, [PROP_STATE]: globalState });
+ const cleanup = () => {
+ linkedDispatch = null;
+ };
+ return cleanup;
+ }, []);
+ const prevGlobalState = useRef(state);
+ notifyListeners(prevGlobalState.current, state);
+ prevGlobalState.current = state;
+ useEffect(() => {
+ globalState = state;
+ }, [state]);
+ };
+
const useGlobalState = (name) => {
if (process.env.NODE_ENV !== 'production') {
validateName(name);
}
- const index = keys.indexOf(name);
- const observedBits = 1 << index;
- const state = useUnstableContextWithoutWarning(Context, observedBits);
- if (state === EMPTY_OBJECT) throw new Error('Please use ');
+ const [partialState, setPartialState] = useState(globalState[name]);
+ useEffect(() => {
+ listeners[name].add(setPartialState);
+ setPartialState(globalState[name]); // in case it's changed before this effect is handled
+ const cleanup = () => {
+ listeners[name].delete(setPartialState);
+ };
+ return cleanup;
+ }, [name]);
const updater = useCallback((u) => setGlobalState(name, u), [name]);
- return [state[name], updater];
+ return [partialState, updater];
};
const getGlobalState = (name) => {
if (process.env.NODE_ENV !== 'production') {
validateName(name);
}
- return wholeState[name];
+ return globalState[name];
};
- const getWholeState = () => wholeState;
+ const getWholeState = () => globalState;
- const setWholeState = (state) => {
- if (listener) {
- listener({ type: UPDATE_STATE, [PROP_STATE]: state });
+ const setWholeState = (nextGlobalState) => {
+ if (linkedDispatch) {
+ linkedDispatch({ type: UPDATE_STATE, [PROP_STATE]: nextGlobalState });
} else {
- wholeState = state;
+ const prevGlobalState = globalState;
+ globalState = nextGlobalState;
+ notifyListeners(prevGlobalState, globalState);
}
};
const dispatchAction = (action) => {
- if (listener) {
- listener(action);
+ if (linkedDispatch) {
+ linkedDispatch(action);
} else {
- wholeState = reducer(wholeState, action);
+ const prevGlobalState = globalState;
+ globalState = reducer(globalState, action);
+ notifyListeners(prevGlobalState, globalState);
}
return action;
};
return {
- [PROP_GLOBAL_STATE_PROVIDER]: GlobalStateProvider,
+ [PROP_USE_GLOBAL_STATE_PROVIDER]: useGlobalStateProvider,
[PROP_SET_GLOBAL_STATE]: setGlobalState,
[PROP_USE_GLOBAL_STATE]: useGlobalState,
[PROP_GET_GLOBAL_STATE]: getGlobalState,
@@ -169,13 +165,13 @@ const createGlobalStateCommon = (reducer, initialState) => {
export const createGlobalState = (initialState) => {
const {
- [PROP_GLOBAL_STATE_PROVIDER]: GlobalStateProvider,
+ [PROP_USE_GLOBAL_STATE_PROVIDER]: useGlobalStateProvider,
[PROP_USE_GLOBAL_STATE]: useGlobalState,
[PROP_SET_GLOBAL_STATE]: setGlobalState,
[PROP_GET_GLOBAL_STATE]: getGlobalState,
} = createGlobalStateCommon((state) => state, initialState);
return {
- GlobalStateProvider,
+ useGlobalStateProvider,
useGlobalState,
setGlobalState,
getGlobalState,
@@ -186,14 +182,14 @@ export const createStore = (reducer, initialState, enhancer) => {
if (!initialState) initialState = reducer(undefined, { type: undefined });
if (enhancer) return enhancer(createStore)(reducer, initialState);
const {
- [PROP_GLOBAL_STATE_PROVIDER]: GlobalStateProvider,
+ [PROP_USE_GLOBAL_STATE_PROVIDER]: useGlobalStateProvider,
[PROP_USE_GLOBAL_STATE]: useGlobalState,
[PROP_GET_WHOLE_STATE]: getWholeState,
[PROP_SET_WHOLE_STATE]: setWholeState,
[PROP_DISPATCH_ACTION]: dispatchAction,
} = createGlobalStateCommon(reducer, initialState);
return {
- GlobalStateProvider,
+ useGlobalStateProvider,
useGlobalState,
getState: getWholeState,
setState: setWholeState, // for devtools.js
diff --git a/tsconfig.json b/tsconfig.json
index ddceef0..c535bb9 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -11,7 +11,7 @@
"sourceMap": true,
"baseUrl": ".",
"paths": {
- "react-hooks-global-state": ["."],
+ "react-hooks-global-state": ["./src"],
"react-hooks-global-state/src/devtools": ["./src/devtools"]
}
}
diff --git a/webpack.config.js b/webpack.config.js
index 591283f..eec99d3 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -38,7 +38,8 @@ module.exports = {
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
alias: {
- 'react-hooks-global-state': __dirname,
+ 'react-hooks-global-state/src/devtools': `${__dirname}/src/devtools`,
+ 'react-hooks-global-state': `${__dirname}/src`,
},
},
devServer: {