Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangfisher committed Jun 9, 2024
1 parent 3a995af commit 17fd0b2
Show file tree
Hide file tree
Showing 12 changed files with 199 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ describe("动态创建计算属性",()=>{
})

store.setState(state=>{
state.user.firstName = "zhang100"
//state.user.firstName = "zhang100"
})

})
Expand Down
72 changes: 72 additions & 0 deletions packages/reactive/src/__tests__/computed.sync.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { test,expect, describe, beforeAll } from "vitest"
import { createStore,ComputedScopeRef,computed, IStore } from ".."


const Account = {
order:{
price:2,
count:3,
total:computed((scope)=>{
return scope.price * scope.count
},{
id:"total",
})
}
}


describe("基本同步计算",()=>{

test("默认同步计算",async ()=>{
const store = createStore({
price:2,
count:3,
total:computed((scope)=>{
return scope.price * scope.count
})
})
store.setState((draft)=>draft.count = 4)
expect(store.state.total).toBe(8)
})
})

describe("Scope指向",()=>{

test("默认Scope指向Current=order",()=>{
return new Promise<void>((resolve)=>{
const store = createStore({
order:{
price:2,
count:3,
total:computed((scope)=>{
expect(scope.price).toBe(2)
expect(scope.count).toBe(3)
resolve()
})
}
})
store.state.order.total // 读取操作时创建计算属性
})

})
test("Scope指向Root",()=>{
return new Promise<void>((resolve)=>{
const store = createStore({
order:{
price:2,
count:3,
total:computed<number>((scope)=>{
expect(scope.order.price).toBe(2)
expect(scope.order.count).toBe(3)
resolve()
return scope.order.price * scope.order.count
})
}
},{
computedScope:()=>ComputedScopeRef.Root
})

store.state.order.total // 读取操作时创建计算属性
})
})
})
26 changes: 7 additions & 19 deletions packages/reactive/src/computed/async.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,12 @@ import { delay } from 'flex-tools/async/delay';
import { OBJECT_PATH_DELIMITER } from '../consts';
import { getComputedContextDraft, getComputedScopeDraft } from '../context';
import { AsyncComputedGetter, AsyncComputedObject, ComputedOptions, ComputedParams, ComputedProgressbar } from './types';
import type { ComputedDescriptor } from './types';
import type { ComputedDescriptor, ComputedRunContext } from './types';
import { IReactiveReadHookParams } from '../reactives/types';
import { ComputedObject } from './computedObject';
import { executeStoreHooks } from './utils';


//
export type AsyncComputedRunContext = {
id : string
name : string
valuePath : string[],
isMutateRunning: boolean
deps : (string | string[])[] // 所依赖的项的路径
resultPath : string[]
getter : AsyncComputedGetter<any>,
values : any[] // 依赖值,即发生变化的项的值
}


/**
* 创建异步计算属性的数据结构
*
Expand Down Expand Up @@ -101,7 +89,7 @@ export function setAsyncComputedObject(stateCtx:any,draft:any,resultPath:string[
* @param scopeDraft
* @param options
*/
async function executeComputedGetter<T extends StoreDefine>(draft:any,computedRunContext:AsyncComputedRunContext,computedOptions:ComputedOptions,store:IStore<T>){
async function executeComputedGetter<T extends StoreDefine>(draft:any,computedRunContext:ComputedRunContext,computedOptions:ComputedOptions,store:IStore<T>){

const { valuePath,getter,resultPath } = computedRunContext;
const { timeout=0,retry=[0,0],selfState } = computedOptions
Expand Down Expand Up @@ -205,7 +193,7 @@ async function executeComputedGetter<T extends StoreDefine>(draft:any,computedRu



function createComputed<T extends StoreDefine>(computedRunContext:AsyncComputedRunContext,computedOptions:ComputedOptions,store:IStore<T>){
function createComputed<T extends StoreDefine>(computedRunContext:ComputedRunContext,computedOptions:ComputedOptions,store:IStore<T>){
const { valuePath, id:mutateId,deps,name:mutateName,resultPath,isMutateRunning,getter } = computedRunContext
const { toComputedResult,selfState,initial,noReentry } = computedOptions

Expand Down Expand Up @@ -243,7 +231,7 @@ function createComputed<T extends StoreDefine>(computedRunContext:AsyncComputedR
return
}
computedRunContext.isMutateRunning=true
computedRunContext.values = values // 即所依赖项的值
computedRunContext.dependValues = values // 即所依赖项的值
try{
return await executeComputedGetter(draft,computedRunContext,finalComputedOptions,store)
}finally{
Expand Down Expand Up @@ -325,12 +313,12 @@ export function createAsyncComputedMutate<T extends StoreDefine>(computedParams
store.options.log(`Create async computed: ${mutateName} (depends=${deps.length==0 ? 'None' : joinValuePath(deps)})`);

// 7. 创建mutate
const computedRunContext:AsyncComputedRunContext = {
const computedRunContext:ComputedRunContext = {
id : computedOptions.id || getComputedId(valuePath,computedOptions.id),
name : selfState ? mutateId : valuePath.join(OBJECT_PATH_DELIMITER),
resultPath : computedResultPath,
isMutateRunning: false,
values : [],
dependValues : [],
valuePath,
deps,
getter
Expand Down
75 changes: 43 additions & 32 deletions packages/reactive/src/computed/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,40 @@
* 同步计算
*/
import { StoreDefine } from "../store/types";
import { getVal, setVal } from "../utils";
import { ComputedDescriptorParams, ComputedGetter, ComputedOptions, RuntimeComputedOptions } from './types';
import { getComputedId, getVal, setVal } from "../utils";
import { ComputedDescriptorParams, ComputedGetter, ComputedOptions, ComputedRunContext, RuntimeComputedOptions } from './types';
import { getComputedContextDraft, getComputedScopeDraft } from '../context';
import { IStore } from '../store/types';
import { IReactiveReadHookParams } from "../reactives/types";
import { ComputedObject } from "./computedObject";
import { executeStoreHooks, getMutateId } from "./utils";

export type ComputedRunContext = {
id : string
name : string
valuePath : string[],
isMutateRunning: boolean
deps : (string | string[])[]
resultPath : string[]
getter : ComputedGetter<any>,
dependValues : any[]
}
import { executeStoreHooks, getComputedTargetPath, getMutateId } from "./utils";
import { OBJECT_PATH_DELIMITER } from "../consts";




function createComputed<T extends StoreDefine>(computedRunContext:ComputedRunContext,computedOptions:ComputedOptions,store:IStore<T>){
const { valuePath, id:mutateId,name:mutateName,resultPath,getter } = computedRunContext
const { selfState } = computedOptions

store.reactiveable.createComputed({
onComputed:({draft,input})=>{
onComputed:({draft,values})=>{
if(!computedOptions.enable){
store.options.log(`Sync computed <${mutateName}> is disabled`,'warn')
return
}
store.options.log(`Run sync computed for : ${mutateName}`);


computedRunContext.dependValues = values

// 1. 根据配置参数获取计算函数的上下文对象
const thisDraft = selfState ? draft : getComputedContextDraft(store,draft,computedRunContext, computedOptions)
const scopeDraft = selfState ? draft : getComputedScopeDraft(store,draft,computedRunContext, computedOptions)

// 2. 执行getter函数
let computedResult = computedOptions.initial;
try {
computedResult = getter.call(thisDraft,scopeDraft);
computedResult = (getter as ComputedGetter<any>).call(thisDraft,scopeDraft);
} catch (e: any) {// 如果执行计算函数出错,则调用
if (typeof computedOptions.onError === "function") {
try {
Expand Down Expand Up @@ -79,37 +73,54 @@ export function createComputedMutate<T extends StoreDefine>(computedParams:IRea
}
// 2. 获取到计算属性描述信息: 包括getter和配置。 此时value是一个函数

let { fn: getter, options: computedOptions } = value() as ComputedDescriptorParams<any>
let { getter, options: computedOptions } = value() as ComputedDescriptorParams<any>


// 2. 运行Hook: 当创建计算属性前时运行hook,本Hook的目的是允许重新指定computedThis或者重新包装原始计算函数
// 3.运行Hook: 用来在创建computed前运行,允许拦截更改计算函数的依赖,上下文,以及getter等
// 运行hook会修改计算配置,所以在hook运行后再读取配置
executeStoreHooks(valuePath,getter,store,computedOptions)
const { selfState } = computedOptions
const computedResultPath:string[] = getComputedTargetPath(computedParams,computedOptions)

// 3. 参数解析:

const [mutateId,mutateName] = getMutateId(valuePath,computedOptions)

store.options.log(`Create sync computed: ${mutateName}`);

const computedRunContext:ComputedRunContext = {
id : computedOptions.id || getComputedId(valuePath,computedOptions.id),
name : selfState ? mutateId : valuePath.join(OBJECT_PATH_DELIMITER),
resultPath : computedResultPath,
isMutateRunning: false,
dependValues : [],
valuePath,
deps : [],
getter
}

createComputed(computedRunContext,computedOptions,store)

// 移花接木原地替换
if(!isExternal) computedParams.replaceValue(getVal(store.stateCtx.state, valuePath));
if(!selfState) computedParams.replaceValue(getVal(store.state, valuePath));

// 5. 创建计算对象实例
const computedObject = {
id:mutateName,
mutate,
group:computedOptions.group,
async:false,
options:computedOptions,
get enable(){return computedOptions.enable as boolean},
set enable(val:boolean){computedOptions.enable=val},
run:(options?:RuntimeComputedOptions)=>{
const params = {desc:mutateId,extraArgs:options}
return isExternal ? computedTo.stateCtx.runMutateTask(params) : store.stateCtx.runMutateTask(params)
}
}
// const computedObject = {
// id:mutateName,
// mutate,
// group:computedOptions.group,
// async:false,
// options:computedOptions,
// get enable(){return computedOptions.enable as boolean},
// set enable(val:boolean){computedOptions.enable=val},
// run:(options?:RuntimeComputedOptions)=>{
// const params = {desc:mutateId,extraArgs:options}
// return isExternal ? computedTo.stateCtx.runMutateTask(params) : store.stateCtx.runMutateTask(params)
// }
// }
const computedObject = new ComputedObject<T>(store,selfState,computedOptions)

store.computedObjects.set(mutateName,computedObject)
return computedObject
}
13 changes: 12 additions & 1 deletion packages/reactive/src/computed/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ export type AsyncComputed<T=any> = (...args: any) => Promise<T>; // 异步计算
// export type ComputedDescriptor<R=any> = StateValueDescriptor<(scope:any) => Promise<R> | R,ComputedOptions<R>>

export interface StateValueDescriptorParams<Fn extends Function,Options extends Dict = Dict> {
fn: Fn
getter: Fn
options:Options
}

Expand All @@ -252,3 +252,14 @@ export type ComputedTarget<T extends Dict = Dict > ={
}


// 执行计算函数时的上下文
export type ComputedRunContext = {
id : string
name : string
valuePath : string[],
isMutateRunning: boolean
deps : (string | string[])[]
resultPath : string[]
getter : ComputedGetter<any> | AsyncComputedGetter<any>,
dependValues : any[]
}
33 changes: 32 additions & 1 deletion packages/reactive/src/computed/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { switchValue } from "flex-tools/misc/switchValue";
import { OBJECT_PATH_DELIMITER } from "../consts";
import { IReactiveReadHookParams } from "../reactives/types";
import { ComputedOptions, ComputedScopeRef, Dict, IStore } from "../types";
import { getComputedId } from "../utils";

Expand Down Expand Up @@ -26,4 +28,33 @@ export function getMutateId(valuePath:string[],computedOptions:ComputedOptions){
const mutateId = computedOptions.id || getComputedId(valuePath,computedOptions.id)
const mutateName =computedOptions.selfState ? mutateId : valuePath.join(OBJECT_PATH_DELIMITER)
return [ mutateId, mutateName ]
}
}


/**
*
* 返回计算属性的目标路径
*
* 即计算结果要写到目标state中的哪一个位置
*
* 计算目标
*
* @param computedParams
* @param computedOptions
* @returns
*/
export function getComputedTargetPath(computedParams:IReactiveReadHookParams,computedOptions:ComputedOptions){
const { path:valuePath } = computedParams;
const {selfState,toComputedResult='self' } = computedOptions

// 如果指定了selfState,即计算结果要写到外部状态中
return selfState ? [valuePath ] : switchValue(toComputedResult,{
self : valuePath,
root : [],
parent : valuePath.slice(0,valuePath.length-2),
current: valuePath.slice(0,valuePath.length-1),
Array : toComputedResult, // 指定一个数组,表示完整路径
String : [...valuePath.slice(0,valuePath.length-1),String(toComputedResult).split(OBJECT_PATH_DELIMITER)],
},{defaultValue:valuePath})

}
Loading

0 comments on commit 17fd0b2

Please sign in to comment.