mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-18 14:56:59 +08:00
feat(infra): livedata (#5562)
LiveData is a reactive data type.
## basic usage
@example
```ts
const livedata = new LiveData(0); // create livedata with initial value
livedata.next(1); // update value
console.log(livedata.value); // get current value
livedata.subscribe(v => { // subscribe to value changes
console.log(v); // 1
});
```
## observable
LiveData is a rxjs observable, you can use rxjs operators.
@example
```ts
new LiveData(0).pipe(
map(v => v + 1),
filter(v => v > 1),
...
)
```
NOTICE: different from normal observable, LiveData will always emit the latest value when you subscribe to it.
## from observable
LiveData can be created from observable or from other livedata.
@example
```ts
const A = LiveData.from(
of(1, 2, 3, 4), // from observable
0 // initial value
);
const B = LiveData.from(
A.pipe(map(v => 'from a ' + v)), // from other livedata
'' // initial value
);
```
NOTICE: LiveData.from will not complete when the observable completes, you can use `spreadComplete` option to change
this behavior.
## Why is it called LiveData
This API is very similar to LiveData in Android, as both are based on Observable, so I named it LiveData.
This commit is contained in:
44
packages/common/infra/src/livedata/react.ts
Normal file
44
packages/common/infra/src/livedata/react.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { use } from 'foxact/use';
|
||||
import { useSyncExternalStore } from 'react';
|
||||
|
||||
import type { LiveData } from './index';
|
||||
|
||||
/**
|
||||
* subscribe LiveData and return the value.
|
||||
*/
|
||||
export function useLiveData<T>(liveData: LiveData<T>): T {
|
||||
return useSyncExternalStore(
|
||||
liveData.reactSubscribe,
|
||||
liveData.reactGetSnapshot
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* subscribe LiveData and return the value. If the value is nullish, will suspends until the value is not nullish.
|
||||
*/
|
||||
export function useEnsureLiveData<T>(liveData: LiveData<T>): NonNullable<T> {
|
||||
const data = useLiveData(liveData);
|
||||
|
||||
if (data === null || data === undefined) {
|
||||
return use(
|
||||
new Promise((resolve, reject) => {
|
||||
const subscription = liveData.subscribe({
|
||||
next(value) {
|
||||
if (value === null || value === undefined) {
|
||||
resolve(value);
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
},
|
||||
error(err) {
|
||||
reject(err);
|
||||
},
|
||||
complete() {
|
||||
reject(new Error('Unexpected completion'));
|
||||
},
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
Reference in New Issue
Block a user