Refactor post threads to use react query (#1851)
* Add post and post-thread queries * Update PostThread components to use new queries * Move from normalized cache to shadow cache model * Merge post shadow into the post automatically * Remove dead code * Remove old temporary session * Fix: set agent on session creation * Temporarily double-login * Handle post-thread uri resolution errors
This commit is contained in:
parent
625cbc435f
commit
fb4f5709c4
12 changed files with 1386 additions and 476 deletions
90
src/state/cache/post-shadow.ts
vendored
Normal file
90
src/state/cache/post-shadow.ts
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
import {useEffect, useState, useCallback, useRef} from 'react'
|
||||
import EventEmitter from 'eventemitter3'
|
||||
import {AppBskyFeedDefs} from '@atproto/api'
|
||||
|
||||
const emitter = new EventEmitter()
|
||||
|
||||
export interface PostShadow {
|
||||
likeUri: string | undefined
|
||||
likeCount: number | undefined
|
||||
repostUri: string | undefined
|
||||
repostCount: number | undefined
|
||||
isDeleted: boolean
|
||||
}
|
||||
|
||||
export const POST_TOMBSTONE = Symbol('PostTombstone')
|
||||
|
||||
interface CacheEntry {
|
||||
ts: number
|
||||
value: PostShadow
|
||||
}
|
||||
|
||||
export function usePostShadow(
|
||||
post: AppBskyFeedDefs.PostView,
|
||||
ifAfterTS: number,
|
||||
): AppBskyFeedDefs.PostView | typeof POST_TOMBSTONE {
|
||||
const [state, setState] = useState<CacheEntry>({
|
||||
ts: Date.now(),
|
||||
value: fromPost(post),
|
||||
})
|
||||
const firstRun = useRef(true)
|
||||
|
||||
const onUpdate = useCallback(
|
||||
(value: Partial<PostShadow>) => {
|
||||
setState(s => ({ts: Date.now(), value: {...s.value, ...value}}))
|
||||
},
|
||||
[setState],
|
||||
)
|
||||
|
||||
// react to shadow updates
|
||||
useEffect(() => {
|
||||
emitter.addListener(post.uri, onUpdate)
|
||||
return () => {
|
||||
emitter.removeListener(post.uri, onUpdate)
|
||||
}
|
||||
}, [post.uri, onUpdate])
|
||||
|
||||
// react to post updates
|
||||
useEffect(() => {
|
||||
// dont fire on first run to avoid needless re-renders
|
||||
if (!firstRun.current) {
|
||||
setState({ts: Date.now(), value: fromPost(post)})
|
||||
}
|
||||
firstRun.current = false
|
||||
}, [post])
|
||||
|
||||
return state.ts > ifAfterTS ? mergeShadow(post, state.value) : post
|
||||
}
|
||||
|
||||
export function updatePostShadow(uri: string, value: Partial<PostShadow>) {
|
||||
emitter.emit(uri, value)
|
||||
}
|
||||
|
||||
function fromPost(post: AppBskyFeedDefs.PostView): PostShadow {
|
||||
return {
|
||||
likeUri: post.viewer?.like,
|
||||
likeCount: post.likeCount,
|
||||
repostUri: post.viewer?.repost,
|
||||
repostCount: post.repostCount,
|
||||
isDeleted: false,
|
||||
}
|
||||
}
|
||||
|
||||
function mergeShadow(
|
||||
post: AppBskyFeedDefs.PostView,
|
||||
shadow: PostShadow,
|
||||
): AppBskyFeedDefs.PostView | typeof POST_TOMBSTONE {
|
||||
if (shadow.isDeleted) {
|
||||
return POST_TOMBSTONE
|
||||
}
|
||||
return {
|
||||
...post,
|
||||
likeCount: shadow.likeCount,
|
||||
repostCount: shadow.repostCount,
|
||||
viewer: {
|
||||
...(post.viewer || {}),
|
||||
like: shadow.likeUri,
|
||||
repost: shadow.repostUri,
|
||||
},
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue