Skip to content

Commit

Permalink
build(3.4.1): automatically unbox atom at all cb logic
Browse files Browse the repository at this point in the history
  • Loading branch information
fantasticsoul committed Nov 27, 2023
1 parent 3b3d031 commit 53660aa
Show file tree
Hide file tree
Showing 34 changed files with 361 additions and 191 deletions.
2 changes: 1 addition & 1 deletion doc/docs/api/atom-and-share/basic-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ const snap = runMutateTask(share2, 'suffixedDesc');
```ts
import { share, syncer, sync } from 'helux';

const [sharedState,,ctx] = share({a:1});
const [sharedState, , ctx] = share({ a: 1 });

// 基于顶层 api 创建 syncer
const mySyncer = syncer(sharedState);
Expand Down
22 changes: 15 additions & 7 deletions doc/docs/api/atom-and-share/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,39 @@ const [numAtom, setAtom] = atom(1);
### 组件外修改

```ts
const changeAtom = (newNum)=> setAtom(newNum);
const changeAtomByDraft = (newNum)=> setAtom(draft=>{ draft.val = newNum });
const changeAtom = (newNum) => setAtom(newNum);
const changeAtomByDraft = (newNum) =>
setAtom((draft) => {
draft.val = newNum;
});
```

### 可变派生

```ts
const [doubleAtom] = atom(0, {
mutate: (draft)=> { draft.val = numAtom.val *2 },
mutate: (draft) => {
draft.val = numAtom.val * 2;
},
});
```

### 全量派生

```ts
const doubuleResult = deriveAtom(()=> numAtom.val * 2 );
const doubuleResult = deriveAtom(() => numAtom.val * 2);
```

### 组件内使用

```ts
function Demo(){
function Demo() {
const [num, setNum] = useAtom(numAtom);
// 此处的调用和 changeAtom changeAtomByDraft 等效
const innerChangeAtom = (newNum)=> setNum(newNum);
const innerChangeAtomByDraft = (newNum)=> setNum(draft=>{ draft.val = newNum });
const innerChangeAtom = (newNum) => setNum(newNum);
const innerChangeAtomByDraft = (newNum) =>
setNum((draft) => {
draft.val = newNum;
});
}
```
51 changes: 25 additions & 26 deletions doc/docs/api/atom-and-share/shared-ctx.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,32 @@ sidebar_position: 2

# 共享上下文

调用`atom``share`会返回共享上下文对象, 对象里的各个方法自动绑定了当前共享对象,让用户可以免去使用顶层api绑定的步骤
调用`atom``share`会返回共享上下文对象, 对象里的各个方法自动绑定了当前共享对象,让用户可以免去使用顶层 api 绑定的步骤

## 获取方式

`atom``share`返回的元组里第三位参数即共享上下文

```ts
// numCtx 即共享上下文对象
const [ numAtom, setNum, numAtomCtx ] = atom(1);
const [numAtom, setNum, numAtomCtx] = atom(1);

// sharedCtx 即共享上下文对象
const [ sharedState, setShared, sharedCtx ] = share({a:1});
const [sharedState, setShared, sharedCtx] = share({ a: 1 });
```

也可以使用`shareAtom``shareState` 接口直接返回共享上下文

```ts
const numCtx = shareAtom(1);
const sharedCtx = shareState({a:1});
const sharedCtx = shareState({ a: 1 });
```

## 可映射为顶层api的方法
## 可映射为顶层 api 的方法

### mutate
`ctx.mutate` 映射顶层api `mutate`

`ctx.mutate` 映射顶层 api `mutate`

```ts
import { mutate } from 'helux';
Expand All @@ -40,25 +41,24 @@ mutate(numAtom)(fn);

### sync & syncer

`ctx.sync` 映射顶层api `sync``ctx.syncer` 映射顶层api `syncer`
`ctx.sync` 映射顶层 api `sync``ctx.syncer` 映射顶层 api `syncer`

```ts
import { sync, syncer } from 'helux';

// 两者等效
const infoSyncer = numAtomCtx.sync(to=>to.val.info.name);
const infoSyncer = sync(numAtomCtx)(to=>to.val.info.name);
const infoSyncer = numAtomCtx.sync((to) => to.val.info.name);
const infoSyncer = sync(numAtomCtx)((to) => to.val.info.name);

// 两者等效
const nameSyncer = numAtomCtx.syncer.name;
const nameSyncer = syncer(numAtom).name;
```


```ts
// 两者等效
const infoSyncer = sharedCtx.sync(to=>to.info.name);
const infoSyncer = sync(numAtomCtx)(to=>to.info.name);
const infoSyncer = sharedCtx.sync((to) => to.info.name);
const infoSyncer = sync(numAtomCtx)((to) => to.info.name);

// 两者等效
const nameSyncer = numAtomCtx.syncer.name;
Expand All @@ -67,23 +67,23 @@ const nameSyncer = syncer(numAtom).name;

### runMutate & runMutateTask

`ctx.runMutate` 映射顶层api `runMutate``ctx.runMutateTask` 映射顶层api `runMutateTask`
`ctx.runMutate` 映射顶层 api `runMutate``ctx.runMutateTask` 映射顶层 api `runMutateTask`

```ts
import { runMutate, runMutateTask } from 'helux';

// 两者等效
numAtomCtx.runMutate('fnName');
runMutate(numAtom)
runMutate(numAtom);

// 两者等效
numAtomCtx.runMutateTask('fnName')
runMutateTask(numAtom)
numAtomCtx.runMutateTask('fnName');
runMutateTask(numAtom);
```

### aciton & acitonAsync

`share` 返回的共享上下文里`aciton``acitonAsync` 方法对应顶层api `aciton``acitonAsync`
`share` 返回的共享上下文里`aciton``acitonAsync` 方法对应顶层 api `aciton``acitonAsync`

```ts
import { aciton, acitonAsync } from 'helux';
Expand All @@ -97,7 +97,7 @@ const myActionAsync = sharedCtx.acitonAsync(actionFnDef);
const myActionAsync = acitonAsync(sharedState)(actionFnDef);
```

`atom` 返回的共享上下文里`aciton``acitonAsync` 方法对应顶层api `atomAciton``atomAcitonAsync`
`atom` 返回的共享上下文里`aciton``acitonAsync` 方法对应顶层 api `atomAciton``atomAcitonAsync`

```ts
import { atomAciton, atomAcitonAsync } from 'helux';
Expand All @@ -119,19 +119,19 @@ const myActionAsync = atomAcitonAsync(numAtom)(actionFnDef);

### useState

`share` 返回的共享上下文里 `useState` 方法对应顶层api `useShared`
`share` 返回的共享上下文里 `useState` 方法对应顶层 api `useShared`

```ts
import { useShared } from 'helux';

// 组件里使用,两者等效
const [ state, setState ] = useShared(sharedState);
const [ state, setState ] = sharedCtx.useState();
const [state, setState] = useShared(sharedState);
const [state, setState] = sharedCtx.useState();
```

### getMutateLoading

`share` 返回的共享上下文里 `getMutateLoading` 方法对应顶层api `getMutateLoading`
`share` 返回的共享上下文里 `getMutateLoading` 方法对应顶层 api `getMutateLoading`

```ts
import { getMutateLoading } from 'helux';
Expand All @@ -143,7 +143,7 @@ const loadingObj = sharedCtx.getMutateLoading();

### useMutateLoading

`share` 返回的共享上下文里 `useMutateLoading` 方法对应顶层api `useMutateLoading`
`share` 返回的共享上下文里 `useMutateLoading` 方法对应顶层 api `useMutateLoading`

```ts
import { getMutateLoading } from 'helux';
Expand All @@ -155,7 +155,7 @@ const loadingObj = sharedCtx.useMutateLoading();

### getActionLoading

`share` 返回的共享上下文里 `getActionLoading` 方法对应顶层api `getActionLoading`
`share` 返回的共享上下文里 `getActionLoading` 方法对应顶层 api `getActionLoading`

```ts
import { getActionLoading } from 'helux';
Expand All @@ -165,10 +165,9 @@ const loadingObj = getActionLoading(sharedState);
const loadingObj = sharedCtx.getActionLoading();
```


### useActionLoading

`share` 返回的共享上下文里 `useActionLoading` 方法对应顶层api `useActionLoading`
`share` 返回的共享上下文里 `useActionLoading` 方法对应顶层 api `useActionLoading`

```ts
import { useActionLoading } from 'helux';
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.3.8",
"version": "3.4.1",
"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
3 changes: 3 additions & 0 deletions packages/helux-core/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { atomMutate, mutate, mutateDict, runMutate, runMutateTask } from './fact
import { atom, share, shareAtom, shareState } from './factory/createShared';
import { sync, syncer } from './factory/createSync';
import { watch } from './factory/createWatch';
import { currentDraftRoot, setAtomVal } from './factory/creator/current';
import { getDeriveLoading, runDerive, runDeriveAsync } from './helpers/fnRunner';
import { getRawState, getSnap } from './helpers/state';
import { useDerived, useDerivedAtom } from './hooks/useDerived';
Expand Down Expand Up @@ -74,6 +75,8 @@ export {
emit,
on,
// util api
currentDraftRoot,
setAtomVal,
storeSrv,
produce,
shallowCompare,
Expand Down
8 changes: 4 additions & 4 deletions packages/helux-core/src/factory/common/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Dict, IMiddlewareCtx, Middleware, MutableDraft } from '../../types/base';
import { Dict, DraftRoot, IMiddlewareCtx, Middleware } from '../../types/base';
import type { TInternal } from '../creator/buildInternal';
import { getRootCtx } from '../root';

Expand All @@ -10,16 +10,16 @@ export function addMiddleware(mid: Middleware) {
/**
* middle only support sync call, so no next fn handler in middleware fn args
*/
export function runMiddlewares(internal: TInternal, draft: MutableDraft, sn: number) {
export function runMiddlewares(internal: TInternal, draftRoot: DraftRoot, draft: DraftRoot, sn: number) {
const { middlewares } = getRootCtx();
if (!middlewares.length) {
return;
}

const data: Dict = {};
const { sharedKey, moduleName } = internal;
const { sharedKey, moduleName, forAtom } = internal;
const setData = (key: string, value: any) => (data[key] = value);
const midCtx: IMiddlewareCtx = { draft, sharedKey, moduleName, setData, idx: 0, sn };
const midCtx: IMiddlewareCtx = { forAtom, draftRoot, draft, sharedKey, moduleName, setData, data, idx: 0, sn };
middlewares.forEach((fn, idx) => {
fn({ ...midCtx, idx });
});
Expand Down
17 changes: 16 additions & 1 deletion packages/helux-core/src/factory/common/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,21 @@ export interface IMutateCtx {
writeKeys: Dict;
arrKeyDict: Dict;
writeKeyPathInfo: Dict<TriggerReason>;
/** TODO :记录变化值的路径,用于异步执行环境合并到 rawState 时,仅合并变化的那一部分节点,避免数据脏写 */
/**
* default: true
* 是否处理 atom setState((draft)=>xxx) 返回结果xxx,
* 目前规则是修改了 draft 则 handleAtomCbReturn 被会置为 false,
* 避免无括号写法 draft=>draft.xx = 1 隐式返回的结果 1 被写入到草稿,
* 备注:安全写法应该是draft=>{draft.xx = 1}
*/
handleAtomCbReturn: boolean;
/**
* TODO :记录变化值的路径,用于异步执行环境合并到 rawState 时,仅合并变化的那一部分节点,避免数据脏写
* 但异步执行环境直接修改 draft 本身就是很危险的行为,该特性需要慎重考虑是否要实现
*/
keyPathValue: Map<string[], any>;
/** 为 atom 记录的 draft.val 引用 */
draftVal: any;
}

// for hot reload of buildShared
Expand Down Expand Up @@ -54,6 +67,8 @@ export function newMutateCtx(options: ISetStateOptions): IMutateCtx {
arrKeyDict: {}, // 记录读取过程中遇到的数组key
writeKeyPathInfo: {},
keyPathValue: new Map(),
handleAtomCbReturn: true,
draftVal: null,
};
}

Expand Down
2 changes: 1 addition & 1 deletion packages/helux-core/src/factory/createAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function innerCreate<T = SharedState>(state: T, options: { fn: Fn; desc: string;
return callMutateFnLogic(state, {
fn,
desc,
getArgs: ({ draft, setState, desc }) => [{ draft, setState, desc, args }],
getArgs: ({ draft, draftRoot, setState, desc }) => [{ draft, draftRoot, setState, desc, args }],
from: 'Action',
});
}; // now fn can have a name 'action' at dev mode
Expand Down
7 changes: 6 additions & 1 deletion packages/helux-core/src/factory/createShared.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { noop } from '@helux/utils';
import { FROM, STATE_TYPE } from '../consts';
import { useAtom, useShared } from '../hooks/useShared';
import type { CoreApiCtx } from '../types/api-ctx';
import type { Dict, Fn, IAtomCreateOptions, IAtomCtx, ICreateOptions, IRunMutateOptions, ISharedCtx } from '../types/base';
import { action, actionAsync, atomAction, atomActionAsync } from './createAction';
import { atomMutate, mutate, runMutate, runMutateTask } from './createMutate';
import { buildSharedObject } from './creator';
import { setAtomVal } from './creator/current';
import { getGlobalEmpty, initGlobalEmpty } from './creator/globalId';
import { initGlobalLoading, initLoadingCtx } from './creator/loading';
import type { IInnerOptions } from './creator/parse';
Expand All @@ -19,13 +21,15 @@ function getFns(state: any, forAtom: boolean) {
actionCreator: atomAction(state),
actionAsyncCreator: atomActionAsync(state),
mutateCreator: atomMutate(state),
setAtomVal, // ctx上也放一个,方便推导类型
};
}
return {
useFn: useShared,
actionCreator: action(state),
actionAsyncCreator: actionAsync(state),
mutateCreator: mutate(state),
setAtomVal: noop, // 非 atom 调用此方法无效,类型上目前不不标记此方法的存在
};
}

Expand All @@ -42,7 +46,7 @@ export function createSharedLogic(innerOptions: IInnerOptions, createOptions?: a
ensureGlobal(apiCtx, stateType);
const { sharedState: state, internal } = buildSharedObject(innerOptions, createOptions);
const { syncer, sync, forAtom, setDraft: setState } = internal;
const { useFn, actionCreator, actionAsyncCreator, mutateCreator } = getFns(state, forAtom);
const { useFn, actionCreator, actionAsyncCreator, mutateCreator, setAtomVal } = getFns(state, forAtom);
const opt = { internal, from: MUTATE, apiCtx };
const ldMutate = initLoadingCtx(createSharedLogic, opt);
const ldAction = initLoadingCtx(createSharedLogic, { ...opt, from: ACTION });
Expand All @@ -64,6 +68,7 @@ export function createSharedLogic(innerOptions: IInnerOptions, createOptions?: a
useActionLoading: ldAction.useLoading,
sync,
syncer,
setAtomVal,
};
}

Expand Down
2 changes: 1 addition & 1 deletion packages/helux-core/src/factory/createSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ function innerCreate(target: any, options: { label: string; forAtom?: boolean; i
const { label, forAtom, isSyncer } = options;
const { sharedKey, rawState, innerSetState } = checkSharedStrict(target, { label, forAtom });
const fn = isSyncer ? createSyncerBuilder : createSyncFnBuilder;
return fn(sharedKey, rawState, innerSetState);
return fn(rawState, { forAtom, sharedKey, setState: innerSetState });
}

export function sync<T extends SharedDict>(target: T) {
Expand Down
2 changes: 1 addition & 1 deletion packages/helux-core/src/factory/creator/buildInternal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function buildInternal(
setDraft: SetAtom | SetState;
asyncSetState: AsyncSetState;
innerSetState: InnerSetState;
setStateImpl: (...any: any[]) => { draft: any; finishMutate: Fn; getPartial: Fn };
setStateImpl: (...any: any[]) => { draftRoot: any; draftNode: any; finishMutate: Fn; getPartial: Fn };
sharedState: Ext<SharedState>;
ruleConf: IRuleConf;
isDeep: boolean;
Expand Down
1 change: 1 addition & 0 deletions packages/helux-core/src/factory/creator/buildShared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export function buildSharedState(options: ParsedOptions) {
},
});
} else {
// TODO 为{}对象型的 atom.val 再包一层监听
sharedState = createOb(rawState, {
set: () => {
warn('changing shared state is invalid');
Expand Down
4 changes: 2 additions & 2 deletions packages/helux-core/src/factory/creator/commitState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { createOb } from '../../helpers/obj';
import type { Dict, IInnerSetStateOptions } from '../../types/base';
import { getDepKeyByPath, IMutateCtx } from '../common/util';
import type { TInternal } from './buildInternal';
import { execDepFnAndInsUpdater } from './updater';
import { execDepFns } from './notify';

export interface ICommitStateOptions extends IInnerSetStateOptions {
state: Dict;
Expand Down Expand Up @@ -72,5 +72,5 @@ export function commitState(opts: ICommitStateOptions) {
}
interveneDeps(true, opts);
interveneDeps(false, opts);
execDepFnAndInsUpdater(opts);
execDepFns(opts);
}
Loading

0 comments on commit 53660aa

Please sign in to comment.