Skip to content

Commit

Permalink
bump: version 0.6.0
Browse files Browse the repository at this point in the history
  • Loading branch information
shenjunru committed Jun 8, 2022
1 parent 087f688 commit 171b1d7
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 52 deletions.
92 changes: 67 additions & 25 deletions lib/cjs/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.markEffectHookIsOnetime = exports.markClassComponentHasSideEffectRender = exports.keepAlive = exports.KeepAlive = void 0;
exports.markEffectHookIsOnetime = exports.markClassComponentHasSideEffectRender = exports.useIgnoreKeepAlive = exports.keepAlive = exports.KeepAlive = void 0;
const react_1 = require("react");
const helpers_1 = require("./helpers");
Object.defineProperty(exports, "markClassComponentHasSideEffectRender", { enumerable: true, get: function () { return helpers_1.markClassComponentHasSideEffectRender; } });
Expand All @@ -11,8 +11,19 @@ const InBrowser = (typeof window !== 'undefined' &&
typeof window.document.createElement !== 'undefined');
const useIsomorphicLayoutEffect = InBrowser ? react_1.useLayoutEffect : react_1.useEffect;
const randomKey = Math.random().toString(36).slice(2);
const KeepAlivePropKey = '__keepAlive$' + randomKey;
const CachesPropKey = ('__keepAliveCaches$' + randomKey);
const MapperPropKey = ('__keepAliveMapper$' + randomKey);
const KeepAliveContext = (0, react_1.createContext)(null);
const KeepAliveProvider = (props) => {
const context = props.value;
(0, react_1.useEffect)(() => () => {
if (context) {
delete context[CachesPropKey];
delete context[MapperPropKey];
}
}, [context]);
return (react_1.default.createElement(KeepAliveContext.Provider, Object.assign({}, props)));
};
class KeepAliveCursor extends react_1.default.Component {
render() {
return null;
Expand All @@ -35,36 +46,53 @@ const KeepAliveEffect = (props) => {
if (rootFiber && effectFiber && renderFiber && finishFiber) {
(0, helpers_1.appendFiberEffect)(rootFiber, effectFiber, renderFiber, finishFiber);
}
}, [context, state]);
(0, react_1.useEffect)(noop, [context, state]);
}, [state]);
(0, react_1.useEffect)(noop, [state]);
return null;
};
const KeepAliveRender = (props) => (react_1.default.createElement(react_1.default.Fragment, null, props.children));
const KeepAliveFinish = () => {
useIsomorphicLayoutEffect(noop);
(0, react_1.useEffect)(noop);
const KeepAliveFinish = (props) => {
const state = props.state;
useIsomorphicLayoutEffect(noop, [state]);
(0, react_1.useEffect)(noop, [state]);
return null;
};
const KeepAliveManage = (props) => {
const name = props.name;
const context = (0, react_1.useContext)(KeepAliveContext);
const cursor = (0, react_1.useRef)(null);
const ignore = (0, react_1.useRef)(true === props.ignore);
const caches = (0, react_1.useMemo)(() => {
const value = (context === null || context === void 0 ? void 0 : context[KeepAlivePropKey]) || new Map();
const value = (context === null || context === void 0 ? void 0 : context[CachesPropKey]) || new Map();
if (context) {
context[KeepAlivePropKey] = value;
context[CachesPropKey] = value;
}
return value;
}, [context]);
ignore.current = true === props.ignore;
}, []);
const mapper = (0, react_1.useMemo)(() => {
const value = (context === null || context === void 0 ? void 0 : context[MapperPropKey]) || new Map();
if (context) {
context[MapperPropKey] = value;
}
return value;
}, []);
const readKey = (0, react_1.useMemo)(() => mapper.get(props.name) || props.name, []);
props.name && mapper.set(props.name, readKey);
const [state, setState] = (0, react_1.useState)(() => {
return [1, ignore.current ? null : caches.get(name)];
const _cache = caches.get(readKey);
caches.delete(readKey);
props.ignore && mapper.forEach((value, key) => {
if (value === readKey) {
mapper.delete(key);
}
});
return props.ignore ? [0, null] : [1, _cache || null];
});
const [step, cache] = state;
const bypass = (0, react_1.useRef)(false);
const ignore = (0, react_1.useRef)(true === props.ignore);
ignore.current = true === props.ignore;
useIsomorphicLayoutEffect(() => () => {
var _a;
if (!context || ignore.current) {
if (!context || !readKey || ignore.current || bypass.current) {
return;
}
const rootFiber = (0, helpers_1.getRootFiber)(context);
Expand All @@ -78,15 +106,14 @@ const KeepAliveManage = (props) => {
return;
}
const restore = (0, helpers_1.protectFiber)(renderFiber);
caches.set(name, [renderFiber, restore]);
}, [context, name]);
caches.set(readKey, [renderFiber, restore]);
}, []);
(0, react_1.useEffect)(() => {
var _a;
if (step !== 1) {
return;
}
if (!context || !name || !cache) {
name && ignore.current && caches.delete(name);
if (!context || !readKey || !cache) {
return setState([0, cache]);
}
const rootFiber = (0, helpers_1.getRootFiber)(context);
Expand All @@ -97,26 +124,26 @@ const KeepAliveManage = (props) => {
}
const boundaryFiber = (0, helpers_1.findParentFiber)(cursorFiber, KeepAliveRender);
if (boundaryFiber) {
bypass.current = true;
return setState([0, null]);
}
caches.delete(name);
const [cachedFiber, restore] = cache;
(0, helpers_1.replaceFiber)(renderFiber, cachedFiber, restore);
return setState([2, null]);
}, [context, state, name]);
}, [state]);
(0, react_1.useEffect)(() => {
if (step === 2) {
setState([0, null]);
}
}, [context, state, name]);
}, [state]);
return (react_1.default.createElement(react_1.default.Fragment, null,
react_1.default.createElement(KeepAliveCursor, { ref: cursor }),
react_1.default.createElement(KeepAliveEffect, { cursor: cursor, name: name, state: state }),
react_1.default.createElement(KeepAliveEffect, { cursor: cursor, name: readKey, state: state }),
react_1.default.createElement(KeepAliveRender, null, null != cache ? null : props.children),
react_1.default.createElement(KeepAliveFinish, null)));
react_1.default.createElement(KeepAliveFinish, { state: state })));
};
exports.KeepAlive = Object.assign(KeepAliveManage, {
Provider: KeepAliveContext.Provider,
Provider: KeepAliveProvider,
});
function keepAlive(Component, getProps) {
return (props) => {
Expand All @@ -127,4 +154,19 @@ function keepAlive(Component, getProps) {
};
}
exports.keepAlive = keepAlive;
const useIgnoreKeepAlive = () => {
const context = (0, react_1.useContext)(KeepAliveContext);
return (0, react_1.useCallback)((name) => {
const caches = context === null || context === void 0 ? void 0 : context[CachesPropKey];
const mapper = context === null || context === void 0 ? void 0 : context[MapperPropKey];
const readKey = mapper === null || mapper === void 0 ? void 0 : mapper.get(name);
readKey && (caches === null || caches === void 0 ? void 0 : caches.delete(readKey));
readKey && (mapper === null || mapper === void 0 ? void 0 : mapper.forEach((value, key) => {
if (value === readKey) {
mapper.delete(key);
}
}));
}, [context]);
};
exports.useIgnoreKeepAlive = useIgnoreKeepAlive;
exports.default = exports.KeepAlive;
91 changes: 66 additions & 25 deletions lib/esm/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
import React, { createContext, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, } from 'react';
import React, { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, } from 'react';
import { markClassComponentHasSideEffectRender, markEffectHookIsOnetime, appendFiberEffect, findFiber, findParentFiber, getRootFiber, protectFiber, replaceFiber, } from './helpers';
function noop() { }
const InBrowser = (typeof window !== 'undefined' &&
typeof window.document !== 'undefined' &&
typeof window.document.createElement !== 'undefined');
const useIsomorphicLayoutEffect = InBrowser ? useLayoutEffect : useEffect;
const randomKey = Math.random().toString(36).slice(2);
const KeepAlivePropKey = '__keepAlive$' + randomKey;
const CachesPropKey = ('__keepAliveCaches$' + randomKey);
const MapperPropKey = ('__keepAliveMapper$' + randomKey);
const KeepAliveContext = createContext(null);
const KeepAliveProvider = (props) => {
const context = props.value;
useEffect(() => () => {
if (context) {
delete context[CachesPropKey];
delete context[MapperPropKey];
}
}, [context]);
return (React.createElement(KeepAliveContext.Provider, { ...props }));
};
class KeepAliveCursor extends React.Component {
render() {
return null;
Expand All @@ -30,35 +41,52 @@ const KeepAliveEffect = (props) => {
if (rootFiber && effectFiber && renderFiber && finishFiber) {
appendFiberEffect(rootFiber, effectFiber, renderFiber, finishFiber);
}
}, [context, state]);
useEffect(noop, [context, state]);
}, [state]);
useEffect(noop, [state]);
return null;
};
const KeepAliveRender = (props) => (React.createElement(React.Fragment, null, props.children));
const KeepAliveFinish = () => {
useIsomorphicLayoutEffect(noop);
useEffect(noop);
const KeepAliveFinish = (props) => {
const state = props.state;
useIsomorphicLayoutEffect(noop, [state]);
useEffect(noop, [state]);
return null;
};
const KeepAliveManage = (props) => {
const name = props.name;
const context = useContext(KeepAliveContext);
const cursor = useRef(null);
const ignore = useRef(true === props.ignore);
const caches = useMemo(() => {
const value = context?.[KeepAlivePropKey] || new Map();
const value = context?.[CachesPropKey] || new Map();
if (context) {
context[KeepAlivePropKey] = value;
context[CachesPropKey] = value;
}
return value;
}, [context]);
ignore.current = true === props.ignore;
}, []);
const mapper = useMemo(() => {
const value = context?.[MapperPropKey] || new Map();
if (context) {
context[MapperPropKey] = value;
}
return value;
}, []);
const readKey = useMemo(() => mapper.get(props.name) || props.name, []);
props.name && mapper.set(props.name, readKey);
const [state, setState] = useState(() => {
return [1, ignore.current ? null : caches.get(name)];
const _cache = caches.get(readKey);
caches.delete(readKey);
props.ignore && mapper.forEach((value, key) => {
if (value === readKey) {
mapper.delete(key);
}
});
return props.ignore ? [0, null] : [1, _cache || null];
});
const [step, cache] = state;
const bypass = useRef(false);
const ignore = useRef(true === props.ignore);
ignore.current = true === props.ignore;
useIsomorphicLayoutEffect(() => () => {
if (!context || ignore.current) {
if (!context || !readKey || ignore.current || bypass.current) {
return;
}
const rootFiber = getRootFiber(context);
Expand All @@ -72,14 +100,13 @@ const KeepAliveManage = (props) => {
return;
}
const restore = protectFiber(renderFiber);
caches.set(name, [renderFiber, restore]);
}, [context, name]);
caches.set(readKey, [renderFiber, restore]);
}, []);
useEffect(() => {
if (step !== 1) {
return;
}
if (!context || !name || !cache) {
name && ignore.current && caches.delete(name);
if (!context || !readKey || !cache) {
return setState([0, cache]);
}
const rootFiber = getRootFiber(context);
Expand All @@ -90,26 +117,26 @@ const KeepAliveManage = (props) => {
}
const boundaryFiber = findParentFiber(cursorFiber, KeepAliveRender);
if (boundaryFiber) {
bypass.current = true;
return setState([0, null]);
}
caches.delete(name);
const [cachedFiber, restore] = cache;
replaceFiber(renderFiber, cachedFiber, restore);
return setState([2, null]);
}, [context, state, name]);
}, [state]);
useEffect(() => {
if (step === 2) {
setState([0, null]);
}
}, [context, state, name]);
}, [state]);
return (React.createElement(React.Fragment, null,
React.createElement(KeepAliveCursor, { ref: cursor }),
React.createElement(KeepAliveEffect, { cursor: cursor, name: name, state: state }),
React.createElement(KeepAliveEffect, { cursor: cursor, name: readKey, state: state }),
React.createElement(KeepAliveRender, null, null != cache ? null : props.children),
React.createElement(KeepAliveFinish, null)));
React.createElement(KeepAliveFinish, { state: state })));
};
export const KeepAlive = Object.assign(KeepAliveManage, {
Provider: KeepAliveContext.Provider,
Provider: KeepAliveProvider,
});
export function keepAlive(Component, getProps) {
return (props) => {
Expand All @@ -119,5 +146,19 @@ export function keepAlive(Component, getProps) {
React.createElement(Component, { ...props })));
};
}
export const useIgnoreKeepAlive = () => {
const context = useContext(KeepAliveContext);
return useCallback((name) => {
const caches = context?.[CachesPropKey];
const mapper = context?.[MapperPropKey];
const readKey = mapper?.get(name);
readKey && caches?.delete(readKey);
readKey && mapper?.forEach((value, key) => {
if (value === readKey) {
mapper.delete(key);
}
});
}, [context]);
};
export { markClassComponentHasSideEffectRender, markEffectHookIsOnetime, };
export default KeepAlive;
6 changes: 5 additions & 1 deletion lib/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ declare type KeepAliveProps = {
children: React.ReactNode;
};
export declare const KeepAlive: React.FC<KeepAliveProps> & {
Provider: React.Provider<HTMLElement | null>;
Provider: React.FC<{
children: React.ReactNode;
value: null | HTMLElement;
}>;
};
export declare function keepAlive<P>(Component: React.ComponentType<P>, getProps: (props: P) => ((Omit<KeepAliveProps, 'children'> & {
key?: React.Key;
}) | string)): React.FC<P>;
export declare const useIgnoreKeepAlive: () => (name: string) => void;
export { markClassComponentHasSideEffectRender, markEffectHookIsOnetime, };
export default KeepAlive;
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-fiber-keep-alive",
"version": "0.5.0",
"version": "0.6.0",
"description": "Keep-Alive for React DOM",
"main": "lib/cjs/index.js",
"module": "lib/esm/index.js",
Expand Down

0 comments on commit 171b1d7

Please sign in to comment.