-
Notifications
You must be signed in to change notification settings - Fork 37
/
posts-list.ts
71 lines (61 loc) · 1.62 KB
/
posts-list.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import { map, type ReadableAtom, type StoreValue } from 'nanostores'
import type { OriginPost } from './post.ts'
export interface PostsListValue {
hasNext: boolean
isLoading: boolean
list: OriginPost[]
}
export type PostsList = {
loading: Promise<OriginPost[]>
next(): Promise<OriginPost[]>
} & ReadableAtom<PostsListValue>
export type PostsListResult = [OriginPost[], PostsListLoader | undefined]
export interface PostsListLoader {
(): Promise<PostsListResult>
}
interface CreatePostsList {
(posts: OriginPost[], loadNext: PostsListLoader | undefined): PostsList
(posts: undefined, loadNext: PostsListLoader): PostsList
}
export const createPostsList: CreatePostsList = (posts, loadNext) => {
let $map = map<StoreValue<PostsList>>({
hasNext: true,
isLoading: true,
list: []
})
let $store = {
...$map,
loading: Promise.resolve([]) as PostsList['loading'],
next
}
let isLoading = false
async function next(): ReturnType<PostsList['next']> {
if (!loadNext) return Promise.resolve([])
if (isLoading) return $store.loading
isLoading = true
$store.setKey('isLoading', true)
$store.loading = loadNext().then(([nextPosts, nextLoader]) => {
loadNext = nextLoader
isLoading = false
$store.set({
hasNext: !!nextLoader,
isLoading: false,
list: $store.get().list.concat(nextPosts)
})
return nextPosts
})
return $store.loading
}
if (posts) {
$store.set({
hasNext: !!loadNext,
isLoading: false,
list: posts
})
} else {
next().catch(() => {
isLoading = false
})
}
return $store
}