Merge pull request #2 from parththakkar106/fix-prepend-autoscroll
Fix: loading earlier turns jumped to the end of the story
This commit is contained in:
@@ -1324,6 +1324,9 @@ export default function Play() {
|
|||||||
// the reader back where they were. See the layout effect below.
|
// the reader back where they were. See the layout effect below.
|
||||||
const restoreScrollRef = useRef(null)
|
const restoreScrollRef = useRef(null)
|
||||||
const loadingOlderRef = useRef(false)
|
const loadingOlderRef = useRef(false)
|
||||||
|
// Earliest time another attempt is allowed after a failure. See the catch
|
||||||
|
// in loadOlder.
|
||||||
|
const retryAfterRef = useRef(0)
|
||||||
|
|
||||||
// The drop cap belongs to the story's first narrated beat. `start` is the
|
// The drop cap belongs to the story's first narrated beat. `start` is the
|
||||||
// scenario's opening prompt, so it's usually that; an adventure begun blank
|
// scenario's opening prompt, so it's usually that; an adventure begun blank
|
||||||
@@ -1367,6 +1370,7 @@ export default function Play() {
|
|||||||
// and two in-flight requests would fetch the same page twice.
|
// and two in-flight requests would fetch the same page twice.
|
||||||
const loadOlder = useCallback(async () => {
|
const loadOlder = useCallback(async () => {
|
||||||
if (loadingOlderRef.current || !hasMore) return
|
if (loadingOlderRef.current || !hasMore) return
|
||||||
|
if (Date.now() < retryAfterRef.current) return
|
||||||
const oldest = actions[0]
|
const oldest = actions[0]
|
||||||
if (!oldest) return
|
if (!oldest) return
|
||||||
loadingOlderRef.current = true
|
loadingOlderRef.current = true
|
||||||
@@ -1374,6 +1378,12 @@ export default function Play() {
|
|||||||
try {
|
try {
|
||||||
const page = await api.getActions(id, { beforeId: oldest.id })
|
const page = await api.getActions(id, { beforeId: oldest.id })
|
||||||
if (page.actions.length) {
|
if (page.actions.length) {
|
||||||
|
// Reading backwards is the opposite of following along, so stop
|
||||||
|
// autoscrolling. Without this the bottom-pinning effect below fires on
|
||||||
|
// the same `actions` change and throws the reader to the end of the
|
||||||
|
// story — worst exactly where the button matters, on a window short
|
||||||
|
// enough that it never scrolled and so never un-pinned itself.
|
||||||
|
pinnedRef.current = false
|
||||||
// Record the height before the prepend; the layout effect below uses
|
// Record the height before the prepend; the layout effect below uses
|
||||||
// it to keep the reader looking at the same paragraph.
|
// it to keep the reader looking at the same paragraph.
|
||||||
restoreScrollRef.current = {
|
restoreScrollRef.current = {
|
||||||
@@ -1391,7 +1401,11 @@ export default function Play() {
|
|||||||
setHasMore(page.has_more)
|
setHasMore(page.has_more)
|
||||||
} catch {
|
} catch {
|
||||||
// Leave hasMore alone: a failed fetch should let the reader try again
|
// Leave hasMore alone: a failed fetch should let the reader try again
|
||||||
// by scrolling, not permanently hide the rest of their story.
|
// by scrolling, not permanently hide the rest of their story. But hold
|
||||||
|
// off briefly first — parked near the top, momentum scrolling fires this
|
||||||
|
// dozens of times a second, and against an endpoint that is failing that
|
||||||
|
// is a retry storm rather than a retry.
|
||||||
|
retryAfterRef.current = Date.now() + 3000
|
||||||
} finally {
|
} finally {
|
||||||
loadingOlderRef.current = false
|
loadingOlderRef.current = false
|
||||||
setLoadingOlder(false)
|
setLoadingOlder(false)
|
||||||
|
|||||||
Reference in New Issue
Block a user