Skip to content

Commit

Permalink
完善类型-新增 isDeepWarch 选项,删除 sameValueExecuteWatch 选项
Browse files Browse the repository at this point in the history
  • Loading branch information
coder-hxl committed Nov 24, 2022
1 parent 57853b0 commit 20f0e5f
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 100 deletions.
150 changes: 86 additions & 64 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import {
IActions,
IStoreArg,
IStoreOptionsArg,
ITrackStore,
IInstance,
IStoreApi,
IArray,
IObject,
} from "./types"
AnyArray,
AnyObject,
IStoreProxy,
ObjectKey
} from './types'

let instanceId = 0
let inDeepProxy = false
Expand All @@ -18,24 +19,25 @@ function verifyActions(actions: IActions) {
for (const key in actions) {
const value = actions[key]

if (typeof value !== "function") {
throw new Error("actions 里只能放函数")
if (typeof value !== 'function') {
throw new Error('actions 里只能放函数')
}
}
}

function verifyState(state: IState) {
if (state === null || typeof state !== "object") {
throw new Error("state 必须是对象")
if (state === null || typeof state !== 'object') {
throw new Error('state 必须是对象')
}
}



function track(instance: IInstance, isEffect = false) {
function addSingleTrack(key: string, callback: Function) {
function track<S extends IState, A extends IActions>(
instance: IInstance<S, A>,
isEffect = false
) {
function addSingleTrack(key: ObjectKey<S>, callback: Function) {
if (isEffect) {
const value = instance.state[key]
const value = instance.state[key as string]
callback(key, value)
}

Expand All @@ -58,7 +60,9 @@ function track(instance: IInstance, isEffect = false) {
}
}

function deleteTrack(trackStore: ITrackStore) {
function deleteTrack<S extends IState, A extends IActions>({
trackStore
}: IInstance<S, A>) {
function deleteSingleTrack(key: string, callback: Function) {
const trackSet = trackStore[key]
if (!trackSet) return
Expand All @@ -77,7 +81,10 @@ function deleteTrack(trackStore: ITrackStore) {
}
}

function execute(instance: IInstance, rootKey: string) {
function execute<S extends IState, A extends IActions>(
instance: IInstance<S, A>,
rootKey: string
) {
const { trackStore } = instance
const value = instance.state[rootKey]
const trackSet = trackStore[rootKey]
Expand All @@ -88,19 +95,24 @@ function execute(instance: IInstance, rootKey: string) {
}
}

function proxyStore(instance: IInstance, storeApi: IStoreApi) {
function proxyStore<S extends IState, A extends IActions>(
instance: IInstance<S, A>,
storeApi: IStoreApi<S>
): IStoreProxy<S, A> {
const { state, actions } = instance

return new Proxy(instance, {
get(_, prop: string) {
if (prop in storeApi) {
return storeApi[prop]
const proxyStoreRes = new Proxy<IStoreProxy<S, A>>(instance as any, {
get(_, prop: any) {
if (prop in instance) {
return instance[prop as ObjectKey<IInstance<S, A>>]
} else if (prop in storeApi) {
return storeApi[prop as ObjectKey<IStoreApi<S>>]
} else if (prop in state) {
return state[prop]
} else if (prop in actions) {
return actions[prop]
} else {
throw new Error(`没有找到 ${prop}`)
throw new Error(`不能获取 ${prop}`)
}
},
set(_, prop: string, value) {
Expand All @@ -114,25 +126,28 @@ function proxyStore(instance: IInstance, storeApi: IStoreApi) {
} else {
throw new Error(`${prop} 请在创建 Store 时添加到 State 或 Actions 中`)
}
},
}
})

return proxyStoreRes
}

function proxyState(
instance: IInstance,
targetObj: IArray | IObject,
function proxyState<S extends IState, A extends IActions>(
instance: IInstance<S, A>,
targetObj: AnyArray | AnyObject,
rootKey: null | string = null
) {
const { sameValueExecuteWatch } = instance.options
const { isDeepWatch } = instance.options

return new Proxy(targetObj, {
set(target, prop: string, value) {
if (!sameValueExecuteWatch && target[prop] === value) return true
// 值不变就无需执行收集到的依赖
if (target[prop] === value) return true

if (inDeepProxy) {
target[prop] = value
return true
} else if (typeof value === "object" && value !== null) {
} else if (isDeepWatch && typeof value === 'object' && value !== null) {
currentRootKey = rootKey ? rootKey : prop
target[prop] = deepProxyState(instance, value)
currentRootKey = null
Expand All @@ -141,34 +156,32 @@ function proxyState(
}

if (rootKey) {
execute(instance, rootKey)
execute<S, A>(instance, rootKey)
} else {
execute(instance, prop)
execute<S, A>(instance, prop)
}

return true
},
}
})
}

function deepProxyState(
instance: IInstance,
rawTarget: IArray | IObject,
function deepProxyState<S extends IState, A extends IActions>(
instance: IInstance<S, A>,
rawTarget: AnyArray | AnyObject,
isRootObj = false
) {
const { isDeepWatch } = instance.options
// 设置根容器
let rootContainer: IArray | IObject = {
}
let rootContainer: AnyArray | AnyObject = {}

if (Array.isArray(rawTarget)) {
rootContainer = []
}

inDeepProxy = true

function recursionProxy(
target: IObject | IArray,
upContainer: IArray | IObject,
target: AnyObject | AnyArray,
upContainer: AnyArray | AnyObject,
isRoot = false
) {
for (const key in target) {
Expand All @@ -186,15 +199,15 @@ function deepProxyState(
2.普通类型
直接赋值给上一个容器
*/
if (typeof value === "object" && value !== null) {
if (typeof value === 'object' && value !== null) {
let container = {}

if (Array.isArray(value)) {
container = []
}

recursionProxy(value, container)
upContainer[key] = proxyState(instance, container, currentRootKey)
upContainer[key] = proxyState<S, A>(instance, container, currentRootKey)
} else {
upContainer[key] = value
}
Expand All @@ -205,18 +218,26 @@ function deepProxyState(
}
}

recursionProxy(rawTarget, rootContainer, isRootObj)

inDeepProxy = false
if (isDeepWatch) {
inDeepProxy = true
recursionProxy(rawTarget, rootContainer, isRootObj)
inDeepProxy = false
} else {
rootContainer = rawTarget
}

return isRootObj
? proxyState(instance, rootContainer)
: proxyState(instance, rootContainer, currentRootKey)
? proxyState<S, A>(instance, rootContainer)
: proxyState<S, A>(instance, rootContainer, currentRootKey)
}

function createStoreInstance(rawState: IState, actions: IActions, options: IStoreOptionsArg) {
function createStoreInstance<S extends IState, A extends IActions>(
rawState: S,
actions: A,
options: IStoreOptionsArg
) {
// 创建实例对象
const instance: IInstance = {
const instance: IInstance<S, A> = {
id: instanceId++,
trackStore: {},
state: {},
Expand All @@ -226,36 +247,37 @@ function createStoreInstance(rawState: IState, actions: IActions, options: IStor

// 实例对象初始化
// 给 state 进行代理
instance.state = deepProxyState(instance, rawState, true)
instance.state = deepProxyState<S, A>(instance, rawState, true)

return instance
}

function createStoreApi(instance: IInstance) {
const { trackStore } = instance

function createStoreApi<S extends IState, A extends IActions>(
instance: IInstance<S, A>
) {
const storeApi = {
watch: track(instance),
watchEffect: track(instance, true),
deleteWatch: deleteTrack(trackStore),
watch: track<S, A>(instance),
watchEffect: track<S, A>(instance, true),
deleteWatch: deleteTrack<S, A>(instance)
}

return storeApi
}

export default function xlStore<S extends IState, A extends IActions>(
store: IStoreArg<S, A>, options: IStoreOptionsArg = {}
): S & A & IStoreApi {
const state = store.state ?? {}
const actions = store.actions ?? {}
store: IStoreArg<S, A>,
options: IStoreOptionsArg = {}
): IStoreProxy<S, A> {
const state = store.state
const actions = store.actions

verifyState(state)
verifyActions(actions)

const instance = createStoreInstance(state, actions, options)
const storeApi = createStoreApi(instance)
const instance = createStoreInstance<S, A>(state, actions, options)
const storeApi = createStoreApi<S, A>(instance)

const storeProxy = proxyStore(instance, storeApi)
const proxyStoreRes = proxyStore<S, A>(instance, storeApi)

return storeProxy as unknown as S & A & IStoreApi
return proxyStoreRes
}
60 changes: 38 additions & 22 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,60 @@
interface IObject extends Object {
export interface AnyObject extends Object {
[key: string]: any
}
interface IArray extends Array<any> {
export interface AnyArray extends Array<any> {
[key: string]: any
}

interface IState extends Object {
/* Store Type */
export type ObjectKey<T> = keyof T

export interface IState extends Object {
[key: string]: any
}

interface IActions extends Object {
export interface IActions extends Object {
[key: string]: Function
}

interface IStoreArg<S, A> {
state?: IState
actions?: A & IActions & ThisType<S & A & IStoreApi>,
}

interface IStoreOptionsArg {
sameValueExecuteWatch?: boolean
export type ITrackStore<S> = {
[Props in keyof S]?: Set<Function>
}

type ITrackStore = {
[key: string]: Set<Function>
export interface IStoreApi<S> {
watch(
key: ObjectKey<S> | ObjectKey<S>[],
callback: (key: string, value: any) => any
): any
watchEffect(
key: ObjectKey<S> | ObjectKey<S>[],
callback: (key: string, value: any) => any
): any
deleteWatch(
key: ObjectKey<S> | ObjectKey<S>[],
callback: (key: string, value: any) => any
): any
}

interface IInstance {
export interface IInstance<S extends IState, A extends IActions> {
id: number
trackStore: ITrackStore
trackStore: ITrackStore<S>
state: IState
actions: IActions,
actions: A & ThisType<IStoreProxy<S, A>>
options: IStoreOptionsArg
}

interface IStoreApi {
watch(key: string | string[], callback: Function): any
watchEffect(key: string | string[], callback: Function): any
deleteWatch(key: string | string[], callback: Function): any
[key: string]: any
export interface IStoreArg<S extends IState, A extends IActions> {
state: S
actions: A & ThisType<IStoreProxy<S, A>>
}

export interface IStoreOptionsArg {
isDeepWatch?: boolean
}

export { IObject, IArray, IState, IActions, IStoreArg, IStoreOptionsArg, ITrackStore, IInstance, IStoreApi }
export type IStoreProxy<S extends IState, A extends IActions> = S &
A &
IStoreApi<S> & {
id: number
trackStore: ITrackStore<S>
}
Loading

0 comments on commit 20f0e5f

Please sign in to comment.