idlize
1/*
2* Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3* Licensed under the Apache License, Version 2.0 (the "License");
4* you may not use this file except in compliance with the License.
5* You may obtain a copy of the License at
6*
7* http://www.apache.org/licenses/LICENSE-2.0
8*
9* Unless required by applicable law or agreed to in writing, software
10* distributed under the License is distributed on an "AS IS" BASIS,
11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* See the License for the specific language governing permissions and
13* limitations under the License.
14*/
15
16import { __context, __id } from "../internals"17import { scheduleCallback } from "../states/GlobalStateManager"18import { ControlledScope, MutableState } from "../states/State"19import { functionOverValue } from "@koalaui/common"20
21/**
22* It calculates the value of the given lambda and caches its result.
23* In contrast to the `remember` function, the given lambda can be recalculated
24* if it uses values of states (including parameters of @memo-functions).
25* If the given lambda does not use any state, it will be calculated only once.
26*
27* @param compute - a function to compute cacheable result
28* @returns the last calculated value
29* @see remember
30* @experimental
31* @memo:intrinsic
32*/
33export function memo<Value>(compute: () => Value): Value {34const scope = __context().scope<Value>(__id(), undefined, undefined, undefined, undefined, undefined)35return scope.unchanged ? scope.cached : scope.recache(compute())36}
37
38/**
39* It calculates the value of the given lambda and caches its result.
40* In contrast to the `memo` function, the given lambda is calculated only once
41* even if it uses values of states (including parameters of @memo-functions).
42*
43* @param compute - a function to compute cacheable result
44* @returns the last calculated value
45* @see memo
46* @memo:intrinsic
47*/
48export function remember<Value>(compute: () => Value): Value {49const scope = __context().scope<Value>(__id(), 0, undefined, undefined, undefined, true) // do not recalculate if used states were updated50return scope.unchanged ? scope.cached : scope.recache(compute())51}
52
53/**
54* It calculates the value of the given lambda, caches its result,
55* and notifies, that this method is removed from the composition.
56*
57* @param compute - a function to compute cacheable result
58* @param cleanup - a function to cleanup computed result on dispose
59* @returns the last calculated value
60* @see remember
61* @memo:intrinsic
62*/
63export function rememberDisposable<Value>(compute: () => Value, cleanup: (value: Value|undefined) => void): Value {64const scope = __context().scope<Value>(__id(), 0, undefined, undefined, cleanup, true) // do not recalculate if used states were updated65return scope.unchanged ? scope.cached : scope.recache(compute())66}
67
68/**
69* Creates remembered state which can be updated from anywhere,
70* and if changed - all depending memo functions recache automatically.
71* Note that you can specify the value directly for primitive values,
72* which do not require computations or memory allocation.
73* It is highly recommended to provide a lambda for all others values.
74*
75* @param initial - initial value supplier used on the state creation
76* @returns a state remembered for the current code position
77* @memo:intrinsic
78*/
79export function rememberMutableState<Value>(initial: (() => Value) | Value): MutableState<Value> {80const scope = __context().scope<MutableState<Value>>(__id(), 0, undefined, undefined, undefined, true) // do not recalculate if used states were updated81return scope.unchanged ? scope.cached : scope.recache(__context()82.mutableState(83functionOverValue<Value>(initial) ?84(initial as (() => Value))() :85(initial as Value),86undefined, undefined, undefined87)88
89)90}
91
92/**
93* Remember mutable state which is computed in async way and is undefined if promise
94* is not fulfilled.
95*
96* @param compute function returning promise to compute the state
97* @param initial value stored to the state
98* @param onError callback called if promise was rejected
99* @memo
100*/
101export function rememberMutableAsyncState<Value>(compute: () => Promise<Value | undefined>, initial?: Value, onError?: (e: Error) => void): MutableState<Value | undefined> {102const result = rememberMutableState<Value | undefined>(initial)103remember(() => {104compute()105.then((value) => result.value = value)106.catch((error: Error) => {107result.value = undefined108onError?.(error)109})110})111return result112}
113
114/**
115* Remember mutable state which is
116* re-computed in async way if key has changed
117* and undefined while promise is not fulfilled.
118*
119* @param key a value to trigger state recomputation
120* @param compute function returning promise to compute the state
121* @param initial value stored to the state
122* @param onError callback called if promise was rejected
123* @memo
124*/
125export function rememberComputableState<Key, Value>(126key: Key,127/** @skip:memo */128compute: (key: Key) => Promise<Value | undefined>,129initial?: Value,130onError?: (e: Error) => void131): MutableState<Value | undefined> {132const result = rememberMutableState<Value | undefined>(initial)133const keyLocal: Key = key // subscribe to a key changes134scheduleCallback(() => ((key: Key) => {135compute(key)136.then((value: Value | undefined): Value | undefined => result.value = value)137.catch((error: Error) => {138result.value = undefined139onError?.(error)140})141})(keyLocal))142return result143}
144
145/**
146* Remember a value which is
147* re-computed in async way if key has changed
148* and undefined while promise is not fulfilled.
149*
150* @param key a value to trigger state recomputation
151* @param compute function returning promise to compute the state
152* @param initial value stored to the state
153* @param onError callback called if promise was rejected
154* @memo
155*/
156export function rememberComputableValue<Key, Value>(157key: Key,158/** @skip:memo */159compute: (key: Key) => Promise<Value | undefined>,160initial?: Value,161onError?: (e: Error) => void162): Value | undefined {163return rememberComputableState(key, compute, initial, onError).value164}
165
166/**
167* @param invalidate - callback that will be notified when any state is modified within the scope
168* @return a user-controlled scope which can be used outside of the incremental update
169* @memo:intrinsic
170*/
171export function rememberControlledScope(invalidate: () => void): ControlledScope {172return __context().controlledScope(__id(), invalidate)173}
174