Skip to content

Commit

Permalink
feat: build(3.4.10): support onRead
Browse files Browse the repository at this point in the history
  • Loading branch information
fantasticsoul committed Dec 2, 2023
1 parent 1e815d4 commit c0d0eab
Show file tree
Hide file tree
Showing 20 changed files with 284 additions and 151 deletions.
4 changes: 2 additions & 2 deletions doc/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ const config = {
docs: {
sidebarPath: require.resolve('./sidebars.js'),
editUrl: ({ docPath }) => {
return `https://holocron.so/github/pr/heluxjs/helux/master/editor/doc/docs/${docPath}`
return `https://holocron.so/github/pr/heluxjs/helux/master/editor/doc/docs/${docPath}`;
},
},
blog: {
showReadingTime: true,
editUrl: ({ docPath }) => {
return `https://holocron.so/github/pr/heluxjs/helux/master/editor/doc/blog/${docPath}`
return `https://holocron.so/github/pr/heluxjs/helux/master/editor/doc/blog/${docPath}`;
},
},
theme: {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "helux",
"version": "3.4.6",
"version": "3.4.10",
"description": "A state library core that integrates atom, signal, collection dep, derive and watch, it supports all react like frameworks( including react 18 ).",
"keywords": [],
"author": {
Expand Down
8 changes: 7 additions & 1 deletion packages/helux-core/src/consts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createSymbol, HAS_SYMBOL } from '../helpers/sym';
export { EVENT_NAME, FROM, LOADING_MODE } from './user';
export { HAS_SYMBOL };

export const VER = '3.4.7';
export const VER = '3.4.10';

export const PROD_FLAG = true;

Expand Down Expand Up @@ -70,3 +70,9 @@ export const STATE_TYPE = {
// fn type
export const DERIVE = 'derive';
export const WATCH = 'watch';

/** 来自 limu 的字典类型表达 */
export const DICT = 'Object';
/** 来自 limu 的数组类型表达 */
export const ARR = 'Array';
export const OTHER = 'Other';
6 changes: 6 additions & 0 deletions packages/helux-core/src/factory/common/sharedScope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ export function diffVal(internal: TInternal, depKey: string) {
}

export function hasChangedNode(internal: TInternal, depKeys: string[], depKey: string) {
// 优先比较自身值有无变化
if (depKeys.includes(depKey) && diffVal(internal, depKey)) {
return true;
}

// 再查找子串值有无变化
let subValChanged = false;
for (const storedDepKey of depKeys) {
// 是 key 的子串,比较值是否有变化
Expand Down
4 changes: 2 additions & 2 deletions packages/helux-core/src/factory/common/stopDep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ function getArrIndexKey(confKey: string, fullKey: string) {
* 辅助 stopDep 主逻辑之用
*/
export function recordArrKey(arrKeys: string[], depKey: string) {
const faterDepKey = matchListItem(arrKeys, depKey);
if (faterDepKey) return;
const parentDepKey = matchListItem(arrKeys, depKey);
if (parentDepKey) return;
nodupPush(arrKeys, depKey);
}

Expand Down
23 changes: 19 additions & 4 deletions packages/helux-core/src/factory/common/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ export interface IMutateCtx {
triggerReasons: TriggerReason[];
ids: NumStrSymbol[];
globalIds: NumStrSymbol[];
/** 记录 depKey 对应值是否是字典 */
isDictInfo: Dict<boolean>;
writeKeys: Dict;
arrKeyDict: Dict;
writeKeyPathInfo: Dict<TriggerReason>;
Expand Down Expand Up @@ -65,7 +63,6 @@ export function newMutateCtx(options: ISetStateOptions): IMutateCtx {
triggerReasons: [],
ids,
globalIds,
isDictInfo: {},
writeKeys: {},
arrKeyDict: {}, // 记录读取过程中遇到的数组 key
writeKeyPathInfo: {},
Expand All @@ -76,7 +73,17 @@ export function newMutateCtx(options: ISetStateOptions): IMutateCtx {
}

export function newOpParams(key: string, value: any, isChange = true): IOperateParams {
return { isChange, op: 'set', key, value, parentType: 'Object', keyPath: [], fullKeyPath: [key], isBuiltInFnKey: false };
return {
isChange,
op: 'set',
key,
value,
proxyValue: value,
parentType: 'Object',
keyPath: [],
fullKeyPath: [key],
isBuiltInFnKey: false,
};
}

export function getDepKeyInfo(depKey: string): DepKeyInfo {
Expand Down Expand Up @@ -142,3 +149,11 @@ export function runPartialCb(forAtom: boolean, mayCb: any, draft: any) {
const val = !isFn(mayCb) ? mayCb : mayCb(draft);
return wrapPartial(forAtom, val);
}

export function chooseVal(mayReplacedVal: any, value: any) {
return mayReplacedVal !== undefined ? mayReplacedVal : value;
}

export function chooseProxyVal(mayReplacedVal: any, proxyVal: any, rawVal: any) {
return mayReplacedVal !== undefined ? { proxyVal: mayReplacedVal, rawVal: mayReplacedVal } : { proxyVal, rawVal };
}
4 changes: 2 additions & 2 deletions packages/helux-core/src/factory/createWatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { SCOPE_TYPE, WATCH } from '../consts';
import { markFnEnd, markFnStart, registerFn } from '../helpers/fnCtx';
import { recordFnDepKeys } from '../helpers/fnDep';
import { getInternal, getSharedKey } from '../helpers/state';
import { getAtomValInternal } from '../hooks/common/shared';
import { getRootValInternal } from '../hooks/common/shared';
import type { Fn, IFnCtx, IWatchFnParams, ScopeType, SharedState, WatchOptionsType } from '../types/base';
import { parseWatchOptions } from './creator/parse';

Expand All @@ -21,7 +21,7 @@ function putSharedToDep(list: any[]) {
if (Array.isArray(list)) {
list.forEach((sharedState: any) => {
// sharedState may a atom val passed useWatch deps fn
const internal = getInternal(sharedState) || getAtomValInternal(sharedState);
const internal = getInternal(sharedState) || getRootValInternal(sharedState);
if (internal) {
const { sharedKey, forAtom } = internal;
// deps 列表里的 atom 结果自动拆箱
Expand Down
17 changes: 12 additions & 5 deletions packages/helux-core/src/factory/creator/buildShared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import { mapSharedState } from '../../helpers/state';
import type { Dict } from '../../types/base';
import { getMarkAtomMap } from '../common/atom';
import { recordLastest } from '../common/blockScope';
import { chooseProxyVal, chooseVal, newOpParams } from '../common/util';
import type { ParsedOptions } from './parse';

/**
* 创建全局使用的共享对象,可提供给 useShared useDerived useWatch derived watch 函数使用
*/
export function buildSharedState(options: ParsedOptions) {
let sharedState: any = {};
const { rawState, sharedKey, deep, forAtom } = options;
const { rawState, sharedKey, deep, forAtom, onRead } = options;
const collectDep = (valKey: string, keyPath: string[], val: any) => {
const depKey = prefixValKey(valKey, sharedKey);
// using shared state in derived/watch callback
Expand All @@ -29,8 +30,13 @@ export function buildSharedState(options: ParsedOptions) {
customKeys: [IS_ATOM as symbol],
customGet: () => forAtom,
onOperate: (params) => {
const { isBuiltInFnKey, fullKeyPath } = params;
!isBuiltInFnKey && collectDep(fullKeyPath.join(KEY_SPLITER), fullKeyPath, params.value);
const { isBuiltInFnKey } = params;
if (!isBuiltInFnKey) {
const { fullKeyPath, value, proxyValue } = params;
const { proxyVal, rawVal } = chooseProxyVal(onRead(params), proxyValue, value);
collectDep(fullKeyPath.join(KEY_SPLITER), fullKeyPath, rawVal);
return proxyVal;
}
},
});
} else {
Expand All @@ -48,8 +54,9 @@ export function buildSharedState(options: ParsedOptions) {
if (isSymbol(key)) {
return val;
}
collectDep(key, [key], val);
return val;
const finalVar = chooseVal(onRead(newOpParams(key, val, false)), val);
collectDep(key, [key], finalVar);
return finalVar;
},
});
}
Expand Down
4 changes: 3 additions & 1 deletion packages/helux-core/src/factory/creator/loading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,9 @@ export function initLoadingCtx(createFn: Fn, options: IInitLoadingCtxOpt) {
if (isUserState && NONE !== loadingMode) {
useLoading = () => {
const loadingProxy = getLoadingInfo(createFn, options).loadingProxy;
const { proxyState, internal, extra, renderInfo } = useSharedLogic(apiCtx, loadingProxy);
const {
insCtx: { proxyState, internal, extra, renderInfo },
} = useSharedLogic(apiCtx, loadingProxy);
// 注意此处用实例的 extra 记录 safeLoading,实例存在期间 safeLoading 创建一次后会被后续一直复用
return [createSafeLoading(extra, proxyState, from), internal.setState, renderInfo];
};
Expand Down
4 changes: 2 additions & 2 deletions packages/helux-core/src/factory/creator/mutateDeep.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { isJsObj, isObj, noop } from '@helux/utils';
import { createDraft, finishDraft, limuUtils } from 'limu';
import type { Dict, IInnerSetStateOptions } from '../../types/base';
import type { Dict, Ext, IInnerSetStateOptions } from '../../types/base';
import { genRenderSN } from '../common/key';
import { runMiddlewares } from '../common/middleware';
import { emitDataChanged } from '../common/plugin';
Expand All @@ -25,7 +25,7 @@ interface ISnCommitOpts extends ICommitOpts {
sn: number;
}

function handlePartial(opts: any) {
function handlePartial(opts: Ext<{ mutateCtx: IMutateCtx }>) {
const { partial, forAtom, mutateCtx, isPrimitive, draftRoot, draftNode } = opts;
// 把深依赖和浅依赖收集到的 keys 合并起来
if (!isObj(partial)) {
Expand Down
53 changes: 28 additions & 25 deletions packages/helux-core/src/factory/creator/notify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ function updateIns(insCtxMap: InsCtxMap, insKey: number, sn: number) {
}
}

/**
* 相关依赖函数执行(render渲染函数,derive派生函数,watch观察函数)
*/
export function execDepFns(opts: ICommitStateOptions) {
const { mutateCtx, internal, desc, isFirstCall, from, sn } = opts;
const { ids, globalIds, depKeys, triggerReasons, isDictInfo } = mutateCtx;
const { ids, globalIds, depKeys, triggerReasons } = mutateCtx;
const { key2InsKeys, id2InsKeys, insCtxMap, rootValKey } = internal;
console.log('depKeys ', depKeys);

internal.ver += 1;
// find associate ins keys
Expand All @@ -36,39 +40,38 @@ export function execDepFns(opts: ICommitStateOptions) {
markFnEnd();
}

const analyzeDepKey = (key: string, skipFindIns?: boolean) => {
const analyzeDepKey = (key: string) => {
// 值相等就忽略
if (!diffVal(internal, key)) {
return;
}

if (!skipFindIns) {
const insKeys = key2InsKeys[key] || [];
let validInsKeys: number[] = insKeys;
const insKeys = key2InsKeys[key] || [];
const validInsKeys: number[] = [];
for (const insKey of insKeys) {
if (allInsKeys.includes(insKey)) {
continue;
}
const insCtx = insCtxMap.get(insKey);
if (!insCtx) {
continue;
}
const depKeys = insCtx.getDeps();

// TODO 支持 compareDict 设置
// 值为字典对象 {},对比 depKey 相关子路径依赖值是否真的发生变化
if (isDictInfo[key]) {
// 重置 validInsKeys,按节点变化去过滤出目标 ins
validInsKeys = [];
for (const insKey of insKeys) {
if (allInsKeys.includes(insKey)) {
continue;
}
const insCtx = insCtxMap.get(insKey);
if (!insCtx) {
continue;
}
const depKeys = insCtx.renderInfo.getDeps();
if (hasChangedNode(internal, depKeys, key)) {
validInsKeys.push(insKey);
}
// 未对 useState useAtom 返回值有任何读操作时
if (depKeys[0] === rootValKey) {
if (diffVal(internal, rootValKey)) {
validInsKeys.push(insKey);
}
continue;
}

allInsKeys = allInsKeys.concat(validInsKeys);
if (hasChangedNode(internal, depKeys, key)) {
validInsKeys.push(insKey);
}
}

allInsKeys = allInsKeys.concat(validInsKeys);
const { firstLevelFnKeys, asyncFnKeys } = getDepFnStats(internal, key, runCountStats);
allFirstLevelFnKeys = allFirstLevelFnKeys.concat(firstLevelFnKeys);
allAsyncFnKeys = allAsyncFnKeys.concat(asyncFnKeys);
Expand All @@ -79,7 +82,7 @@ export function execDepFns(opts: ICommitStateOptions) {
// 因这里补上 rootValKey 仅为了查 watch derive 函数,故刻意传递 skipFindIns = true 跳过 ins 查询
// 否则会导致不该更新的实例也触发更新了,影响精确更新结果
if (!depKeys.includes(rootValKey)) {
analyzeDepKey(rootValKey, true);
analyzeDepKey(rootValKey);
}
// clear cached diff result
clearDiff();
Expand All @@ -100,7 +103,7 @@ export function execDepFns(opts: ICommitStateOptions) {
allAsyncFnKeys.forEach((fnKey) => markComputing(fnKey, runCountStats[fnKey]));
allFirstLevelFnKeys.forEach((fnKey) => runFn(fnKey, { sn, from, triggerReasons, internal, desc, isFirstCall }));

// start update
// start trigger rerender
allInsKeys.forEach((insKey) => updateIns(insCtxMap, insKey, sn));
// start update globalId ins
if (globalInsKeys.length) {
Expand Down
7 changes: 3 additions & 4 deletions packages/helux-core/src/factory/creator/operateState.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { matchDictKey, nodupPush, prefixValKey } from '@helux/utils';
import { IOperateParams, limuUtils } from 'limu';
import { IOperateParams } from 'limu';
import type { KeyIdsDict, NumStrSymbol } from '../../types/base';
import { cutDepKeyByStop } from '../common/stopDep';
import { getDepKeyByPath, IMutateCtx } from '../common/util';
import type { TInternal } from './buildInternal';

export function handleOperate(opParams: IOperateParams, opts: { internal: TInternal; mutateCtx: IMutateCtx }) {
const { isChange, fullKeyPath, keyPath, parentType, value } = opParams;
const { isChange, fullKeyPath, keyPath, parentType } = opParams;
const { internal, mutateCtx } = opts;
const { arrKeyDict } = mutateCtx;
if (!isChange) {
Expand All @@ -20,7 +20,7 @@ export function handleOperate(opParams: IOperateParams, opts: { internal: TInter
// const oldVal = getVal(internal.snap, fullKeyPath);
// if (opParams.value === oldVal) return;
const { moduleName, exact, sharedKey, ruleConf, level1ArrKeys } = internal;
const { writeKeyPathInfo, ids, globalIds, writeKeys, isDictInfo } = mutateCtx;
const { writeKeyPathInfo, ids, globalIds, writeKeys } = mutateCtx;
mutateCtx.level1Key = fullKeyPath[0];
mutateCtx.handleAtomCbReturn = false;

Expand All @@ -34,7 +34,6 @@ export function handleOperate(opParams: IOperateParams, opts: { internal: TInter
const { idsDict, globalIdsDict, stopDepInfo } = ruleConf;
const writeKey = getDepKeyByPath(fullKeyPath, sharedKey);
writeKeyPathInfo[writeKey] = { sharedKey, moduleName, keyPath: fullKeyPath };
isDictInfo[writeKey] = limuUtils.isObject(value);

// 设定了非精确更新策略时,提取出第一层更新路径即可
if (!exact) {
Expand Down
2 changes: 2 additions & 0 deletions packages/helux-core/src/factory/creator/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ export function parseOptions(innerOptions: IInnerOptions, options: ICreateOption
const rules = options.rules || [];
const before = options.before || noop;
const mutate = options.mutate || noop;
const onRead = options.onRead || noop;
// 后续 parseRules 步骤会转 stopArrDep stopDepth 到 stopDepInfo 上
const stopArrDep = options.stopArrDep ?? true;
const stopDepth = options.stopDepth || STOP_DEPTH;
Expand All @@ -179,6 +180,7 @@ export function parseOptions(innerOptions: IInnerOptions, options: ICreateOption
before,
mutate,
mutateFnDict,
onRead,
stateType,
loadingMode,
stopArrDep,
Expand Down
Loading

0 comments on commit c0d0eab

Please sign in to comment.