remove list jitter by initially preferring ssr
This commit is contained in:
parent
eeaf6e10e5
commit
90f4d41fc8
|
@ -8,19 +8,21 @@ import { CommentFlat } from './comment'
|
|||
import { SUB_ITEMS } from '../fragments/subs'
|
||||
import { LIMIT } from '../lib/cursor'
|
||||
import ItemFull from './item-full'
|
||||
import { useData } from './use-data'
|
||||
|
||||
export default function Items ({ ssrData, variables = {}, query, destructureData, rank, noMoreText, Footer, filter = () => true }) {
|
||||
const { data, fetchMore } = useQuery(query || SUB_ITEMS, { variables })
|
||||
const Foooter = Footer || MoreFooter
|
||||
const dat = useData(data, ssrData)
|
||||
|
||||
const { items, pins, cursor } = useMemo(() => {
|
||||
if (!data && !ssrData) return {}
|
||||
if (!dat) return {}
|
||||
if (destructureData) {
|
||||
return destructureData(data || ssrData)
|
||||
return destructureData(dat)
|
||||
} else {
|
||||
return data?.items || ssrData?.items
|
||||
return dat?.items
|
||||
}
|
||||
}, [data, ssrData])
|
||||
}, [dat])
|
||||
|
||||
const pinMap = useMemo(() =>
|
||||
pins?.reduce((a, p) => { a[p.position] = p; return a }, {}), [pins])
|
||||
|
@ -28,7 +30,7 @@ export default function Items ({ ssrData, variables = {}, query, destructureData
|
|||
const Skeleton = useCallback(() =>
|
||||
<ItemsSkeleton rank={rank} startRank={items?.length} limit={variables.limit} />, [rank, items])
|
||||
|
||||
if (!ssrData && !data) {
|
||||
if (!dat) {
|
||||
return <Skeleton />
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import styles from './notifications.module.css'
|
|||
import { useServiceWorker } from './serviceworker'
|
||||
import { Checkbox, Form } from './form'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useData } from './use-data'
|
||||
|
||||
function Notification ({ n, fresh }) {
|
||||
const type = n.__typename
|
||||
|
@ -340,10 +341,11 @@ const nid = n => n.__typename + n.id + n.sortTime
|
|||
export default function Notifications ({ ssrData }) {
|
||||
const { data, fetchMore } = useQuery(NOTIFICATIONS)
|
||||
const router = useRouter()
|
||||
const dat = useData(data, ssrData)
|
||||
|
||||
const { notifications: { notifications, lastChecked, cursor } } = useMemo(() => {
|
||||
return data || ssrData || { notifications: {} }
|
||||
}, [data, ssrData])
|
||||
return dat || { notifications: {} }
|
||||
}, [dat])
|
||||
|
||||
useEffect(() => {
|
||||
if (lastChecked && !router?.query?.checkedAt) {
|
||||
|
@ -358,7 +360,7 @@ export default function Notifications ({ ssrData }) {
|
|||
}
|
||||
}, [router, lastChecked])
|
||||
|
||||
if (!data && !ssrData) return <CommentsFlatSkeleton />
|
||||
if (!dat) return <CommentsFlatSkeleton />
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.fresh {
|
||||
background-color: rgba(0, 0, 0, 0.03);
|
||||
background-color: rgba(128, 128, 128, 0.1);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import { useEffect, useRef, useState } from 'react'
|
||||
|
||||
/*
|
||||
What we want is to use ssrData if it exists, until cache data changes
|
||||
... this prevents item list jitter where the intially rendered items
|
||||
are stale until the cache is rewritten with incoming ssrData
|
||||
*/
|
||||
export function useData (data, ssrData) {
|
||||
// when fresh is true, it means data has been updated after the initial render and it's populated
|
||||
const [fresh, setFresh] = useState(false)
|
||||
|
||||
// on first render, we want to use ssrData if it's available
|
||||
// it's only unavailable on back/forward navigation
|
||||
const ref = useRef(true)
|
||||
const firstRender = ref.current
|
||||
ref.current = false
|
||||
|
||||
useEffect(() => {
|
||||
if (!firstRender && !fresh && data) setFresh(true)
|
||||
}, [data])
|
||||
|
||||
// if we don't have data yet, use ssrData
|
||||
// if we have data, but it's not fresh, use ssrData
|
||||
// unless we don't have ssrData
|
||||
if (!data || (!fresh && ssrData)) return ssrData
|
||||
return data
|
||||
}
|
|
@ -7,6 +7,7 @@ import userStyles from './user-header.module.css'
|
|||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { useQuery } from '@apollo/client'
|
||||
import MoreFooter from './more-footer'
|
||||
import { useData } from './use-data'
|
||||
|
||||
// all of this nonsense is to show the stat we are sorting by first
|
||||
const Stacked = ({ user }) => (<span>{abbrNum(user.stacked)} stacked</span>)
|
||||
|
@ -37,6 +38,7 @@ function seperate (arr, seperator) {
|
|||
|
||||
export default function UserList ({ ssrData, query, variables, destructureData }) {
|
||||
const { data, fetchMore } = useQuery(query, { variables })
|
||||
const dat = useData(data, ssrData)
|
||||
const [statComps, setStatComps] = useState(seperate(STAT_COMPONENTS, Seperator))
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -48,15 +50,15 @@ export default function UserList ({ ssrData, query, variables, destructureData }
|
|||
}, [variables?.by])
|
||||
|
||||
const { users, cursor } = useMemo(() => {
|
||||
if (!data && !ssrData) return {}
|
||||
if (!dat) return {}
|
||||
if (destructureData) {
|
||||
return destructureData(data || ssrData)
|
||||
return destructureData(dat)
|
||||
} else {
|
||||
return data || ssrData
|
||||
return dat
|
||||
}
|
||||
}, [data, ssrData])
|
||||
}, [dat])
|
||||
|
||||
if (!ssrData && !data) {
|
||||
if (!dat) {
|
||||
return <UsersSkeleton />
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue