From fb4b144bbbe7c9d91ba5835e633f54dc672981db Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Thu, 8 Dec 2022 15:29:36 -0500 Subject: [PATCH] Started work on initializers --- .../docs/api-reference/CollectionInstance.mdx | 3 +- .../plexus-core/src/collection/collection.ts | 5 +- packages/plexus-core/src/collection/data.ts | 11 +++-- packages/plexus-core/src/index.ts | 4 +- packages/plexus-core/src/initializer.ts | 8 ++++ packages/plexus-core/src/state.ts | 9 ++-- packages/plexus-core/src/watchable.ts | 37 +++++++++++++-- packages/plexus-react/src/index.ts | 2 +- packages/plexus-react/src/useInit.ts | 46 +++++++++++-------- .../src/shared/itemManipulation.ts | 12 +++++ 10 files changed, 100 insertions(+), 37 deletions(-) create mode 100644 packages/plexus-core/src/initializer.ts diff --git a/docs/docs/api-reference/CollectionInstance.mdx b/docs/docs/api-reference/CollectionInstance.mdx index dd72c6af..d9108675 100644 --- a/docs/docs/api-reference/CollectionInstance.mdx +++ b/docs/docs/api-reference/CollectionInstance.mdx @@ -136,7 +136,8 @@ A Collection Instance

Get the Value of the data item with the provided key (the raw data). If there - is not an existing data item, this will return a provisional one + is not an existing data item, this will return a provisional one (an + empty untracked data instance)

**Returns**: this

The new Collection Instance

diff --git a/packages/plexus-core/src/collection/collection.ts b/packages/plexus-core/src/collection/collection.ts index 08ea96d8..78689a7a 100644 --- a/packages/plexus-core/src/collection/collection.ts +++ b/packages/plexus-core/src/collection/collection.ts @@ -349,7 +349,7 @@ export class CollectionInstance< return this } /** - * Get the Value of the data item with the provided key (the raw data). If there is not an existing data item, this will return a _provisional_ one + * Get the Value of the data item with the provided key (the raw data). If there is not an existing data item, this will return a _provisional_ one (an empty untracked data instance) * @param {string|number} dataKey The key of the data item to get * @returns {this} The new Collection Instance */ @@ -469,7 +469,8 @@ export class CollectionInstance< */ createGroup( groupName: Name, - config?: PlexusCollectionGroupConfig + config?: PlexusCollectionGroupConfig, + fetcher?: (currentValue?: DataType) => DataType ) { this.mount() if (this._internalStore._groups.has(groupName)) return this diff --git a/packages/plexus-core/src/collection/data.ts b/packages/plexus-core/src/collection/data.ts index 94f1f20d..e7d625df 100644 --- a/packages/plexus-core/src/collection/data.ts +++ b/packages/plexus-core/src/collection/data.ts @@ -123,7 +123,7 @@ export class CollectionData< // loop through the foreign keys for (idKey of Object.keys(foreignKeys ?? {})) { - const isArray = foreignKeys[idKey]?.mode === 'array'; + const isArray = foreignKeys[idKey]?.mode === 'array' const newKey = foreignKeys[idKey]?.newKey as string const foreignCollectionName = foreignKeys[idKey]?.reference as string const foreignCollection = this.instance().findReference( @@ -132,9 +132,12 @@ export class CollectionData< // if we have a shallow value, then we can try to get the fresh value from the foreign collection if (this.shallowValue) { - const freshValue = isArray ? - this.shallowValue?.[idKey]?.map((id: string) => foreignCollection?.getItem(id).shallowValue) || undefined - : foreignCollection?.getItem(this.shallowValue?.[idKey]).shallowValue || undefined + const freshValue = isArray + ? this.shallowValue?.[idKey]?.map( + (id: string) => foreignCollection?.getItem(id).shallowValue + ) || undefined + : foreignCollection?.getItem(this.shallowValue?.[idKey]) + .shallowValue || undefined if ( freshValue && foreignCollection?.config.foreignKeys?.[idKey]?.newKey diff --git a/packages/plexus-core/src/index.ts b/packages/plexus-core/src/index.ts index e2f8f289..4b5b596b 100644 --- a/packages/plexus-core/src/index.ts +++ b/packages/plexus-core/src/index.ts @@ -30,8 +30,8 @@ import { LiteralType, AlmostAnything } from '@plexusjs/utils' export function state< Literal extends PlexusStateType = any, Value = Literal extends AlmostAnything ? Literal : LiteralType ->(item: Value) { - return _state(() => instance(), item) +>(item: Value, fetcher?: (currentValue?: Value) => Value) { + return _state(() => instance(), item, fetcher) } /** * Generate a Plexus State diff --git a/packages/plexus-core/src/initializer.ts b/packages/plexus-core/src/initializer.ts new file mode 100644 index 00000000..01e3c0a5 --- /dev/null +++ b/packages/plexus-core/src/initializer.ts @@ -0,0 +1,8 @@ +import { Watchable } from '.' + +export function WatchableInitializer( + watchable: Watchable, + initFunction: (currentValue?: ValueType) => ValueType +) { + watchable +} diff --git a/packages/plexus-core/src/state.ts b/packages/plexus-core/src/state.ts index 71ce8eda..f95df8e7 100644 --- a/packages/plexus-core/src/state.ts +++ b/packages/plexus-core/src/state.ts @@ -42,9 +42,9 @@ export class StateInstance< constructor( instance: () => PlexusInstance, init: StateValue, - fetcher?: (currentValue: StateValue) => StateValue + fetcher?: (currentValue?: StateValue) => StateValue ) { - super(instance, init) + super(instance, init, fetcher) this.instance = instance this._internalStore = { _name: '', @@ -267,9 +267,10 @@ export class StateInstance< export function _state( instance: () => PlexusInstance, - _init: StateValue + _init: StateValue, + fetcher?: (currentValue?: StateValue) => StateValue ) { // Returned Object // - return new StateInstance(instance, _init) + return new StateInstance(instance, _init, fetcher) } diff --git a/packages/plexus-core/src/watchable.ts b/packages/plexus-core/src/watchable.ts index e74ec4b7..f5fa158a 100644 --- a/packages/plexus-core/src/watchable.ts +++ b/packages/plexus-core/src/watchable.ts @@ -9,6 +9,7 @@ interface WatchableStore { _nextValue: Value _watchers: Set> _internalId: string + _initialized: boolean } type HistorySeed = { @@ -22,15 +23,26 @@ type HistorySeed = { export class Watchable { protected _watchableStore: WatchableStore protected instance: () => PlexusInstance + protected initFetcher: ((currentValue?: ValueType) => ValueType) | undefined + private loading: boolean = false + public get isLoading() { + return this.loading + } + /** * The internal id of the computed state */ get id(): string { return `${this._watchableStore._internalId}` } - constructor(instance: () => PlexusInstance, init: ValueType) { + constructor( + instance: () => PlexusInstance, + init: ValueType, + fetcher?: (currentValue?: ValueType) => ValueType + ) { this.instance = instance this._watchableStore = { + _initialized: false, _internalId: instance().genId(), _nextValue: init, _value: init, @@ -39,6 +51,14 @@ export class Watchable { _lastValue: null, _watchers: new Set(), } + this.initFetcher = fetcher + ? (currentValue?: ValueType) => { + this.loading = true + const newValue = fetcher?.(currentValue) + this.loading = false + return newValue || init + } + : undefined } watch( @@ -54,6 +74,13 @@ export class Watchable { } } get value(): ValueType { + if (this._watchableStore._initialized === false && this.initFetcher) { + this._watchableStore._value = + this.initFetcher?.(this._watchableStore._value) || + this._watchableStore._value + this._watchableStore._publicValue = deepClone(this._watchableStore._value) + this._watchableStore._initialized = true + } return this._watchableStore._publicValue } } @@ -62,8 +89,12 @@ export class WatchableMutable< ValueType extends NonNullable = any > extends Watchable { private _history: HistorySeed | undefined - constructor(instance: () => PlexusInstance, init: ValueType) { - super(instance, init) + constructor( + instance: () => PlexusInstance, + init: ValueType, + fetcher?: (currentValue?: ValueType) => ValueType + ) { + super(instance, init, fetcher) } /** diff --git a/packages/plexus-react/src/index.ts b/packages/plexus-react/src/index.ts index 550cf414..492b66a4 100644 --- a/packages/plexus-react/src/index.ts +++ b/packages/plexus-react/src/index.ts @@ -4,4 +4,4 @@ export { useEvent } from './useEvent' export { useDeposit } from './useDeposit' -export { useInit } from './useInit' \ No newline at end of file +export { useInit } from './useInit' diff --git a/packages/plexus-react/src/useInit.ts b/packages/plexus-react/src/useInit.ts index 4736fb9a..9321a248 100644 --- a/packages/plexus-react/src/useInit.ts +++ b/packages/plexus-react/src/useInit.ts @@ -1,32 +1,38 @@ -import { PlexusAction, Watchable } from '@plexusjs/core'; -import { FunctionType, InnerFunction } from '@plexusjs/core/dist/action'; -import { useEffect, useState } from 'react'; -import { usePlexus, PlexusValue, PlexusValueArray } from './usePlexus'; +import { PlexusAction, Watchable } from '@plexusjs/core' +import { FunctionType, InnerFunction } from '@plexusjs/core/dist/action' +import { useEffect, useState } from 'react' +import { usePlexus, PlexusValue, PlexusValueArray } from './usePlexus' export type PlexusInitReturn = { - value: T; - loading: boolean; + value: T + loading: boolean } // Singleton argument -export function useInit(deps: V, action: InnerFunction): PlexusInitReturn> +export function useInit( + deps: V, + action: InnerFunction +): PlexusInitReturn> // array argument export function useInit( deps: V | [], - action: InnerFunction + action: InnerFunction ): PlexusInitReturn> -export function useInit (deps: typeof usePlexus.arguments[0], action: InnerFunction) { - const value = usePlexus(deps); - const [loading, setLoading] = useState(true); +export function useInit( + deps: typeof usePlexus.arguments[0], + action: InnerFunction +) { + const value = usePlexus(deps) + const [loading, setLoading] = useState(true) - useEffect(() => { - setLoading(true); - action().then(() => setLoading(false)); - }, [action]) + useEffect(() => { + setLoading(true) + action().then(() => setLoading(false)) + }, [action]) - return { - loading, - value - } -} \ No newline at end of file + return { + loading, + value, + } +} diff --git a/packages/plexus-utils/src/shared/itemManipulation.ts b/packages/plexus-utils/src/shared/itemManipulation.ts index 1447b1b5..70921fed 100644 --- a/packages/plexus-utils/src/shared/itemManipulation.ts +++ b/packages/plexus-utils/src/shared/itemManipulation.ts @@ -147,3 +147,15 @@ export function isEqual(a: NonNullable, b: NonNullable): boolean { } return false } + +/** + * + */ +// export function asyncNormalizer< +// InputFunction extends () => Promise | unknown +// >( +// inputFunction: InputFunction +// ): [ReturnType | undefined, Error | undefined] { + +// // return [inputFunction()] +// }