Skip to content

Commit

Permalink
Merge pull request #3 from Leland-Kwong/develop
Browse files Browse the repository at this point in the history
Refactor and improve lifecycle management
  • Loading branch information
leland-kwong authored Jan 25, 2022
2 parents e51c9b6 + fe4c216 commit b6e9be1
Show file tree
Hide file tree
Showing 30 changed files with 970 additions and 406 deletions.
6 changes: 5 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,9 @@
"plugin:prettier/recommended",
"next/core-web-vitals"
],
"plugins": ["prettier"]
"plugins": ["@typescript-eslint", "prettier"],
"rules": {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "error"
}
}
14 changes: 3 additions & 11 deletions dist/AtomDevTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,26 +42,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.AtomDevTools = void 0;
var react_1 = __importStar(require("react"));
var constants_1 = require("./constants");
var utils_1 = require("./utils");
function AtomObserver(_a) {
var onChange = _a.onChange, _b = _a.onLifeCycle, onLifeCycle = _b === void 0 ? constants_1.noop : _b;
var rootDb = (0, react_1.useContext)(constants_1.RootContext);
var rootDb = (0, utils_1.useDb)();
(0, react_1.useEffect)(function () {
var onLifeCycleWrapper = function (data) {
var refKeys = Array.from(rootDb.activeRefKeys.values());
var activeHooks = Object.fromEntries(refKeys.map(function (key) { return [
key,
rootDb.subscriptions.listenerCount(key)
]; }));
onLifeCycle(__assign(__assign({}, data), { activeHooks: activeHooks }));
onLifeCycle(data);
};
var subscriptions = [
rootDb.subscriptions.on(constants_1.$$internal, onChange),
rootDb.subscriptions.on(constants_1.$$lifeCycleChannel, onLifeCycleWrapper)
];
rootDb.subscriptions.emit(constants_1.$$lifeCycleChannel, {
type: constants_1.LIFECYCLE_MOUNT,
key: constants_1.$$lifeCycleChannel
});
return function () {
subscriptions.forEach(function (unsubscribe) { return unsubscribe(); });
};
Expand Down
5 changes: 2 additions & 3 deletions dist/AtomRoot.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.AtomRoot = void 0;
var react_1 = __importDefault(require("react"));
var db_1 = require("./db");
var react_2 = require("react");
var constants_1 = require("./constants");
var utils_1 = require("./utils");
function AtomRoot(_a) {
var children = _a.children;
var rootDb = (0, react_2.useContext)(constants_1.RootContext);
var isNestedAtomRoot = rootDb !== constants_1.defaultContext;
var currentDb = (0, utils_1.useDb)();
var isNestedAtomRoot = currentDb !== constants_1.defaultContext;
if (isNestedAtomRoot) {
throw new Error((0, utils_1.errorMsg)('Application tree may only be wrapped in a single `AtomRoot` component'));
}
Expand Down
6 changes: 1 addition & 5 deletions dist/core.d.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import type { AtomRef } from './types';
export type { AtomRef } from './types';
export { useIsNew } from './utils';
export { AtomDevTools } from './AtomDevTools';
export { AtomRoot } from './AtomRoot';
export declare function atomRef<T>({ key, defaultState }: {
key: AtomRef<T>['key'];
defaultState: AtomRef<T>['defaultState'];
}): Readonly<AtomRef<T>>;
export declare function atomRef<T>({ key, defaultState, resetOnInactive }: AtomRef<T>): Readonly<AtomRef<T>>;
export declare function useRead<T, SelectorValue = T>(atomRef: AtomRef<T>, selector: (state: T) => SelectorValue): SelectorValue;
export declare function useSend<T>(atomRef: AtomRef<T>): <Payload>(mutationFn: (oldState: T, payload: Payload) => T, payload: Payload) => Promise<[void, void]>;
export declare function useReset<T>(atomRef: AtomRef<T>): () => Promise<[void, void]>;
37 changes: 15 additions & 22 deletions dist/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ var __assign = (this && this.__assign) || function () {
return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.useReset = exports.useSend = exports.useRead = exports.atomRef = exports.AtomRoot = exports.AtomDevTools = exports.useIsNew = void 0;
exports.useReset = exports.useSend = exports.useRead = exports.atomRef = exports.AtomRoot = exports.AtomDevTools = void 0;
var react_1 = require("react");
var constants_1 = require("./constants");
var db_1 = require("./db");
var lifecycle_1 = require("./lifecycle");
var mutable_1 = require("./mutable");
var utils_1 = require("./utils");
function defaultTo(defaultValue, value) {
return value === undefined ? defaultValue : value;
}
Expand All @@ -36,69 +36,62 @@ function checkDuplicateAtomKey(key) {
}
return key;
}
var utils_1 = require("./utils");
Object.defineProperty(exports, "useIsNew", { enumerable: true, get: function () { return utils_1.useIsNew; } });
var AtomDevTools_1 = require("./AtomDevTools");
Object.defineProperty(exports, "AtomDevTools", { enumerable: true, get: function () { return AtomDevTools_1.AtomDevTools; } });
var AtomRoot_1 = require("./AtomRoot");
Object.defineProperty(exports, "AtomRoot", { enumerable: true, get: function () { return AtomRoot_1.AtomRoot; } });
function atomRef(_a) {
var key = _a.key, defaultState = _a.defaultState;
var key = _a.key, defaultState = _a.defaultState, _b = _a.resetOnInactive, resetOnInactive = _b === void 0 ? true : _b;
var actualKey = checkDuplicateAtomKey(key);
var ref = {
key: actualKey,
defaultState: defaultState
defaultState: defaultState,
resetOnInactive: resetOnInactive
};
mutable_1.mutable.atomRefsByKey.set(actualKey, ref);
return ref;
}
exports.atomRef = atomRef;
function useRead(atomRef, selector) {
var key = atomRef.key, defaultState = atomRef.defaultState;
var rootDb = (0, react_1.useContext)(constants_1.RootContext);
var rootDb = (0, utils_1.useDb)();
var initialStateSlice = (0, db_1.getState)(rootDb)[key];
var _a = (0, react_1.useState)(selector(defaultTo(defaultState, initialStateSlice))), hookState = _a[0], setHookState = _a[1];
(0, react_1.useEffect)(function () {
var watcherFn = function (_a) {
var newState = _a.newState;
var oldState = _a.oldState, newState = _a.newState;
var prev = oldState[key];
var stateSlice = newState[key];
var nextValue = selector(defaultTo(defaultState, stateSlice));
var hasChanged = hookState !== nextValue;
var hasChanged = prev !== nextValue;
if (!hasChanged) {
return;
}
setHookState(nextValue);
};
return rootDb.subscriptions.on(key, watcherFn);
}, [
rootDb,
key,
hookState,
selector,
defaultState,
atomRef
]);
(0, lifecycle_1.useLifeCycle)(rootDb, atomRef);
}, [rootDb, key, selector, defaultState, atomRef]);
(0, lifecycle_1.useLifeCycle)(atomRef, 'read');
return hookState;
}
exports.useRead = useRead;
function useSend(atomRef) {
var key = atomRef.key, defaultState = atomRef.defaultState;
var rootDb = (0, react_1.useContext)(constants_1.RootContext);
(0, lifecycle_1.useLifeCycle)(rootDb, atomRef);
var rootDb = (0, utils_1.useDb)();
(0, lifecycle_1.useLifeCycle)(atomRef, 'send');
return (0, react_1.useMemo)(function () {
return function (mutationFn, payload) {
var _a;
if (process.env.NODE_ENV === 'development' &&
!mutationFn.name) {
console.error('Warning: This mutation function should be named -', mutationFn);
}
var key = atomRef.key, defaultState = atomRef.defaultState;
var rootState = (0, db_1.getState)(rootDb);
var stateSlice = defaultTo(defaultState, rootState[key]);
var nextState = __assign(__assign({}, rootState), (_a = {}, _a[key] = mutationFn(stateSlice, payload), _a));
return (0, db_1.setState)(rootDb, nextState, atomRef, mutationFn, payload);
};
}, [defaultState, rootDb, key, atomRef]);
}, [rootDb, atomRef]);
}
exports.useSend = useSend;
function useReset(atomRef) {
Expand Down
2 changes: 1 addition & 1 deletion dist/db.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function makeDb(initialState) {
return {
state: initialState,
subscriptions: subscriptions,
activeRefKeys: new Set()
activeHooks: {}
};
}
exports.makeDb = makeDb;
Expand Down
1 change: 1 addition & 0 deletions dist/extras/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './use-cache';
17 changes: 17 additions & 0 deletions dist/extras/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"use strict";
/*
* Extras are modules exported for external usage as
* additional utilities that are separate from core.
* */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
__exportStar(require("./use-cache"), exports);
8 changes: 8 additions & 0 deletions dist/extras/use-cache.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Returns a new function that compares the old return value
* and new return value. If they are the same, then it will
* return what was previously returned. This is useful for
* determining if two different objects are equal to prevent
* unecessary rerenders.
*/
export declare function useIsNew<X, Y>(fn: (x: X) => Y, isNewValue?: (prev: Y, next: Y) => boolean): (x: X) => Y;
44 changes: 44 additions & 0 deletions dist/extras/use-cache.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.useIsNew = void 0;
var react_1 = require("react");
function shallowCompare(cache, value) {
var maybeNewValue = value !== cache;
if (maybeNewValue) {
var shouldShallowCompare = typeof cache === 'object';
if (shouldShallowCompare) {
for (var _i = 0, _a = Object.keys(value); _i < _a.length; _i++) {
var key = _a[_i];
var prev = cache[key];
var next = value[key];
var isNewValue = prev !== next;
if (isNewValue) {
return true;
}
}
return false;
}
}
return cache !== value;
}
/**
* Returns a new function that compares the old return value
* and new return value. If they are the same, then it will
* return what was previously returned. This is useful for
* determining if two different objects are equal to prevent
* unecessary rerenders.
*/
function useIsNew(fn, isNewValue) {
if (isNewValue === void 0) { isNewValue = shallowCompare; }
var cache = (0, react_1.useRef)(null);
return function (x) {
var next = fn(x);
var shouldUpdateCache = cache.current === null ||
isNewValue(cache.current, next);
if (shouldUpdateCache) {
cache.current = next;
}
return cache.current;
};
}
exports.useIsNew = useIsNew;
1 change: 1 addition & 0 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './core';
export * from './extras';
export * as examples from './examples';
1 change: 1 addition & 0 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ var __importStar = (this && this.__importStar) || function (mod) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.examples = void 0;
__exportStar(require("./core"), exports);
__exportStar(require("./extras"), exports);
exports.examples = __importStar(require("./examples"));
9 changes: 7 additions & 2 deletions dist/lifecycle.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
import type { AtomRef, Db } from './types';
export declare function useLifeCycle(db: Db<any>, atomRef: AtomRef<any>): void;
import type { AtomRef, Db, LifeCycleEventData } from './types';
export declare function useLifeCycle(atomRef: AtomRef<any>, hookType: keyof Db<any>['activeHooks']): void;
export declare function useOnLifeCycle<T>(atomRef: AtomRef<T>, fn: (data: {
type: string;
activeHooks: Db<T>['activeHooks'];
state: Db<T>['state'];
}) => void, predicate?: (data: LifeCycleEventData, atomRef: AtomRef<T>) => boolean): import("emittery").UnsubscribeFn;
Loading

0 comments on commit b6e9be1

Please sign in to comment.