Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangfisher committed Jun 4, 2024
1 parent b59a67d commit 90bb587
Show file tree
Hide file tree
Showing 12 changed files with 109 additions and 49 deletions.
55 changes: 53 additions & 2 deletions packages/reactive/src/computed/async.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { OBJECT_PATH_DELIMITER } from '../consts';
import { getComputedRefDraft } from '../context';
import { AsyncComputedGetter, AsyncComputedObject, ComputedOptions, ComputedParams, ComputedProgressbar, RuntimeComputedOptions } from './types';
import type { ComputedDescriptor, ComputedObject, ComputedTarget, IComputeParams } from './types';
import { IReactiveReadHookParams } from '../reactives/types';


/**
Expand Down Expand Up @@ -194,10 +195,10 @@ export function setAsyncComputedObject(stateCtx:any,draft:any,resultPath:string[
* @param stateCtx
* @param params
*/
export function createAsyncComputedMutate<T extends StoreDefine>(computedParams:IComputeParams,store:IStore<T>,computedTo?:ComputedTarget) :ComputedObject<T> | undefined{
export function createAsyncComputedMutate<T extends StoreDefine>(computedParams:IReactiveReadHookParams,store:IStore<T>,computedTo?:ComputedTarget) :ComputedObject<T> | undefined{

// 1. 参数检查
const { fullKeyPath:valuePath, parent ,value } = computedParams;
const { path:valuePath, parent ,value } = computedParams;
// 排除掉所有非own属性,例如valueOf等
if (parent && !Object.hasOwn(parent, valuePath[valuePath.length - 1])) {
return;
Expand Down Expand Up @@ -245,6 +246,56 @@ export function createAsyncComputedMutate<T extends StoreDefine>(computedParams
store.options.log(`Create async computed: ${mutateName} (depends=${deps.length==0 ? 'None' : joinValuePath(deps)})`);

// 7. 创建mutate

const mutateObject = store.reactiveable.createComputed({
// 指定依赖
depends:(draft)=>getDepValues(deps,draft, valuePath),
// 初始化计算函数
initial:(draft)=>{
if(isExternal){
// @ts-ignore
computedTo.stateCtx.setState((draft)=>{
Object.assign(draft,createAsyncComputedObject(computedTo.stateCtx,mutateId,{result: initial}))
})
}else{
if(toComputedResult=='self'){ // 原地替换
setVal(draft, valuePath, createAsyncComputedObject(store.stateCtx, mutateId,{result: initial}))
}else{ // 更新到其他地方
setAsyncComputedObject(store.stateCtx,draft,computedResultPath, mutateId,{result: initial})
// 删除原始的计算属性
const p = getVal(draft,valuePath.slice(0,valuePath.length-1))
delete p[valuePath[valuePath.length-1]]
}
}
},
onComputed:async ({draft,setState,input,options})=>{
if(!computedOptions.enable && input?.enable!==true){
store.options.log(`Async computed <${mutateName}> is disabled`,'warn')
return
}
store.options.log(`Run async computed for : ${mutateName}`);
const finalComputedOptions = Object.assign({},computedOptions,input) as Required<ComputedOptions>
if(noReentry && isMutateRunning && store.options.debug) {
store.options.log(`Reentry async computed: ${mutateName}`,'warn');
return
}
isMutateRunning=true
try{
return await executeComputedGetter.call<IStore<T>,any[],any>(store,draft,getter,{
input,
computedResultPath,
computedOptions:finalComputedOptions,
computedContext: computedParams,
setState
},computedTo)
}finally{
isMutateRunning=false
}
},
getter:()=>{},
options:computedOptions
})

const mutate =store.stateCtx.mutate({
// 依赖是相于对根对象的
deps: (state: any) =>{
Expand Down
13 changes: 6 additions & 7 deletions packages/reactive/src/computed/computed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,12 @@ export function computed<R = any,ExtraAttrs extends Dict = {}>( getter: any,depe
// 解析参数:同时支持同步和异步计算函数两种方式声明
let deps:ComputedDepends = []
const opts : ComputedOptions<R,ExtraAttrs> = {
async: false,
enable:true,
timeout:0,
depends: [],
toComputedResult:ComputedScopeRef.Self,
// scope:ComputedScopeRef.Current,
immediate:true,
async : false,
enable : true,
timeout : 0,
depends : [],
toComputedResult: ComputedScopeRef.Self,
immediate : true,
}

if(arguments.length==1){
Expand Down
12 changes: 6 additions & 6 deletions packages/reactive/src/computed/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { Dict, IStore } from "../types"
import { AsyncComputedGetter, ComputedOptions, ComputedParams, IComputeParams } from "../computed/types"
import { computed } from "./computed"
import { installComputed } from "./install"
import { getRndId } from "../utils/getRndId"
import { IReactiveReadHookParams } from "../reactives/types"



Expand Down Expand Up @@ -60,10 +62,8 @@ export type ComputedObjectCreateOptions<R = any,ExtraAttrs extends Dict = {}> =

return <R = any,ExtraAttrs extends Dict = {}>(getter:AsyncComputedGetter<R>,options?:ComputedObjectCreateOptions<R,ExtraAttrs>)=>{
const opts = Object.assign({
id:"s"+Math.random().toString(16).substring(2),
// 由于计算函数不是声明在状态中,没有所谓的valuePath,scope取值Self,Parent,Root等无效,因此需要手动指定
// 否则默认指向的是stateCtx.state
scope:store.stateCtx.state,
id:getRndId(),
scope:store.stateCtx.state,
context:store.stateCtx.state
},options) as ComputedObjectCreateOptions<R,ExtraAttrs>

Expand All @@ -78,10 +78,10 @@ export type ComputedObjectCreateOptions<R = any,ExtraAttrs extends Dict = {}> =
// 当computed在state中声明时可以获取所在位置的fullKeyPath,parent,而使用createComputed时就没有这些信息
// 需要自行构建,并传递一个targetCtx,
const computedParams = {
fullKeyPath: [],
path: [],
parent: null,
value: computed(getter, opts.depends, options)
} as unknown as IComputeParams
} as unknown as IReactiveReadHookParams
installComputed(computedParams,store)
return targetCtx
}
Expand Down
8 changes: 4 additions & 4 deletions packages/reactive/src/computed/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ import { isAsyncFunction } from "flex-tools/typecheck/isAsyncFunction";
import { IStore, StoreDefine } from "../store/types";
import { ComputedObject, ComputedTarget } from "./types";
import { createAsyncComputedMutate } from "./async";
import { createComputedMutate } from "./sync";
import { IComputeParams } from "./types";
import { createComputedMutate } from "./sync";
import { IReactiveReadHookParams } from "../reactives/types";

/**
* 安装计算函数
* @param options
*/


export function installComputed<T extends StoreDefine>(params:IComputeParams,store:IStore<T>,computedTo?:ComputedTarget) {
export function installComputed<T extends StoreDefine>(params:IReactiveReadHookParams,store:IStore<T>,computedTo?:ComputedTarget) {

const descriptor = params.value
let computedObject:ComputedObject<T> | undefined
Expand Down Expand Up @@ -48,7 +48,7 @@ export function installComputed<T extends StoreDefine>(params:IComputeParams,sto
// 当创建计算完毕后的回调
if(computedObject && typeof(store.options.onCreateComputedObject)=='function'){
try{
store.options.onCreateComputedObject(params.fullKeyPath,computedObject)
store.options.onCreateComputedObject(params.path,computedObject)
}catch(e:any){
store.options.log(e.stack,'error')
}
Expand Down
9 changes: 5 additions & 4 deletions packages/reactive/src/computed/sync.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
/**
* 同步计算
*/
import { ComputedScopeRef, StoreDefine, StoreOptions } from "../store/types";
import { ComputedScopeRef, StoreDefine } from "../store/types";
import { getComputedId, getVal, setVal } from "../utils";
import { OBJECT_PATH_DELIMITER } from '../consts';
import { ComputedDescriptorParams, ComputedObject, ComputedTarget, IComputeParams, RuntimeComputedOptions } from './types';
import { ComputedDescriptorParams, ComputedObject, ComputedTarget, RuntimeComputedOptions } from './types';
import { getComputedRefDraft } from "../context"
import { IStore } from '../store/types';
import { IReactiveReadHookParams } from "../reactives/types";

/**
* 为同步计算属性生成mutate
* @param stateCtx
* @param computedParams
*/

export function createComputedMutate<T extends StoreDefine>(computedParams:IComputeParams,store:IStore<T>,computedTo?:ComputedTarget) :ComputedObject<T> | undefined{
export function createComputedMutate<T extends StoreDefine>(computedParams:IReactiveReadHookParams,store:IStore<T>,computedTo?:ComputedTarget) :ComputedObject<T> | undefined{

// 1. 获取计算属性的描述
const { fullKeyPath:valuePath, parent,value } = computedParams;
const {path:valuePath, parent,value } = computedParams;
let { fn: getter, options: computedOptions } = value() as ComputedDescriptorParams<any>
// 排除掉所有非own属性,例如valueOf等
if (parent && !Object.hasOwn(parent, valuePath[valuePath.length - 1])) {
Expand Down
14 changes: 7 additions & 7 deletions packages/reactive/src/reactive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import { sharex } from "helux"
import { createUseState } from "./store/useState"
import { ComputedState, Dict, RuntimeComputedOptions } from "./types"

export function reactive<T extends Dict=Dict>(data:T) {
const stateCtx = sharex<ComputedState<T>>(data)
return {
...stateCtx,
useState:createUseState<T>(stateCtx)
}
// export function reactive<T extends Dict=Dict>(data:T) {
// const stateCtx = sharex<ComputedState<T>>(data)
// return {
// ...stateCtx,
// useState:createUseState<T>(stateCtx)
// }

}
// }



Expand Down
7 changes: 4 additions & 3 deletions packages/reactive/src/reactives/helux.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,18 @@ export class HeluxReactiveable<T extends Dict =Dict> extends Reactiveable<T>{
createComputed(params: CreateComputedOptions<ComputedState<T>>): string {
const {initial,onComputed,depends,options} = params
this._stateCtx.mutate({
// 收集依赖
deps: (state: any) =>{
return depends
return depends(state)
},
// 初始化计算属性
fn: (draft, params) => {
if (params.isFirstCall) {
// @ts-ignore
initial(draft, params)
}
},
// 此函数在依赖变化时执行,用来异步计算
// extraArgs是在调用run方法时传入的额外参数,可用来覆盖计算参数
// extraArgs是在调用run方法时传入的额外计算参数,可用来覆盖计算参数
task: async ({ draft, setState, input, extraArgs }) => {
// @ts-ignore
return onComputed({draft,setState,input,options:Object.assign({},extraArgs)})
Expand Down
9 changes: 5 additions & 4 deletions packages/reactive/src/reactives/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import { ComputedDepends, ComputedOptions, ComputedState, Dict, RequiredComputed


export type CreateComputedOptions<T extends ComputedState<Dict> =ComputedState<Dict>>= {
depends?:ComputedDepends // 依赖的计算属性
depends:(state:T)=>any[] // 依赖的计算属性
initial(state:T,params:any):void // 首次计算时执行
getter():void // 计算函数
// 当依赖变化时执行
onComputed(params:{
draft:T,
setState:(state:T)=>void,
input:any,
draft:T, // 草稿对象
setState:(state:T)=>void, // 更新状态
input:any, // 输入参数,即依赖变化后的值[]
options?: ComputedOptions
}):void // 当依赖变化时执行
options:ComputedOptions // 计算属性的选项
Expand Down Expand Up @@ -77,3 +77,4 @@ export class Reactiveable<T extends Dict = Dict>{

}


8 changes: 5 additions & 3 deletions packages/reactive/src/store/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import mitt,{Emitter} from "mitt";
import { createUseWatch } from '../watch/useWatch';
import { getRndId } from "../utils/getRndId";
import { HeluxReactiveable } from "../reactives/helux";
import { Reactiveable } from "../reactives/types";



Expand All @@ -22,7 +23,7 @@ export function createStore<T extends StoreDefine = StoreDefine>(data:T,options?
computedThis : ()=>ComputedScopeRef.Root,
computedScope: ()=>ComputedScopeRef.Current,
singleton : true,
reactiveable : true,

},options) as StoreOptions<T>

opts.log = (...args:any[])=>{
Expand All @@ -48,17 +49,18 @@ export function createStore<T extends StoreDefine = StoreDefine>(data:T,options?

// 3. 创建响应式对象, 此处使用helux
store.reactiveable = new HeluxReactiveable<T>(data,{
id:opts.id,
onRead: (params) => {
installExtends<T>(params,store as IStore<T>);
}
})
}) as Reactiveable<ComputedState<T>>


store.stateCtx = sharex<ComputedState<T>>(data as any, {
stopArrDep: false,
moduleName: opts.id,
onRead: (params) => {
installExtends<T>(params,store as IStore<T>);
installExtends<T>(params as any,store as IStore<T>);
}
});
store.state = store.stateCtx.reactive
Expand Down
8 changes: 6 additions & 2 deletions packages/reactive/src/store/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type { createUseState } from "./useState";
import type { createSetState } from "./setState";
import { Emitter } from "mitt";
import { IReactive } from "../reactive";
import { IReactiveable } from "../reactives";
import { Reactiveable } from "../reactives";


export type StoreDefine<State extends Dict = Dict> = State
Expand Down Expand Up @@ -70,6 +70,10 @@ export interface StoreOptions<T extends StoreDefine= StoreDefine>{
* 当计算对象创建时调用
*/
onCreateComputedObject(keyPath:string[],computedObject:ComputedObject<T>):void
/**
* 提供一个响应式核心
*/
reactiveable?:Reactiveable
}


Expand All @@ -91,7 +95,7 @@ export type IStore<T extends StoreDefine= StoreDefine> = {
// 启用与停止计算
enableComputed : (value:boolean)=>void
options : StoreOptions<T>
reactiveable : IReactiveable<ComputedState<T>>
reactiveable : Reactiveable<T>
stateCtx : ISharedCtx<ComputedState<T>>
reactive : IReactive<T>
// 计算
Expand Down
9 changes: 5 additions & 4 deletions packages/reactive/src/watch/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@ import { IStore, StoreDefine } from "../store/types"
import { IComputeParams } from "../types"
import { setVal } from "../utils"
import { WatchDescriptor } from "./types"
import { IReactiveReadHookParams } from "../reactives/types"

/**
* 安装一个watch函数
* @param params
* @param store
* @param watchTo
*/
export function installWatch<T extends StoreDefine>(params:IComputeParams,store:IStore<T>) {
export function installWatch<T extends StoreDefine>(params:IReactiveReadHookParams,store:IStore<T>) {

store.options.log(`install watch for <${params.fullKeyPath.length==0 ? "Dynamic" : params.fullKeyPath.join(OBJECT_PATH_DELIMITER)}>`)
store.options.log(`install watch for <${params.path.length==0 ? "Dynamic" : params.path.join(OBJECT_PATH_DELIMITER)}>`)

const watchDescriptor = params.value() as WatchDescriptor

watchDescriptor.options.selfPath = params.fullKeyPath
watchDescriptor.options.selfPath = params.path

// 创建一个侦听对象
const watchObject = store.watchObjects.add(watchDescriptor)
Expand All @@ -31,7 +32,7 @@ export function installWatch<T extends StoreDefine>(params:IComputeParams,store:
params.replaceValue(watchDescriptor.options.initial)
// @ts-ignore
store.stateCtx.setState((draft)=>{
setVal(draft,params.fullKeyPath,watchDescriptor.options.initial)
setVal(draft,params.path,watchDescriptor.options.initial)
})
flush(store.stateCtx.state as any)
}
Expand Down
6 changes: 3 additions & 3 deletions packages/reactive/src/watch/useWatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { sharex } from "helux"
import { installWatch } from "./install"
import { WatchDescriptor, WatchDependParams, WatchListener, WatchOptions } from "./types"
import { normalizedWatchFilter } from "./utils"
import { IReactiveReadHookParams } from "../reactives/types"
/**
* createWatch的hook版本
*
Expand All @@ -21,8 +22,7 @@ export function createUseWatch<T extends StoreDefine>(store:IStore<T>){
return <Value = any,Result=Value>(listener:WatchListener<Value,Result>,depends:WatchDependParams<Value>,options?:WatchOptions<Result>)=>{
useEffect(() => {
const params = {
fullKeyPath: ['value'],
keyPath: [],
path: ['value'],
parent: undefined,
value: () => {
const descr = {
Expand All @@ -38,7 +38,7 @@ export function createUseWatch<T extends StoreDefine>(store:IStore<T>){
} as WatchDescriptor
return descr
}
} as unknown as IComputeParams
} as unknown as IReactiveReadHookParams
// 安装
const watchObject = installWatch(params,store)
return ()=>{
Expand Down

0 comments on commit 90bb587

Please sign in to comment.