diff --git a/frontend/src/app/scratch/[slug]/ScratchEditor.tsx b/frontend/src/app/scratch/[slug]/ScratchEditor.tsx index 78b07f79..8fa6522e 100644 --- a/frontend/src/app/scratch/[slug]/ScratchEditor.tsx +++ b/frontend/src/app/scratch/[slug]/ScratchEditor.tsx @@ -1,6 +1,6 @@ "use client" -import { useState } from "react" +import { useEffect, useState } from "react" import useSWR from "swr" @@ -46,6 +46,23 @@ export default function ScratchEditor({ initialScratch, parentScratch, initialCo setScratch(scratch => ({ ...scratch, owner: cached.owner })) } + // On initial page load, request the latest scratch from the server, and + // update `scratch` if it's newer. + // This can happen when navigating back to a scratch page that was already loaded, but + // was updated, so the originally-loaded initialScratch prop becomes stale. + // https://github.com/decompme/decomp.me/issues/711 + useEffect(() => { + api.get(scratch.url).then((updatedScratch: api.Scratch) => { + const updateTime = new Date(updatedScratch.last_updated) + const scratchTime = new Date(scratch.last_updated) + + if (scratchTime < updateTime) { + console.info("Client got updated scratch", updatedScratch) + setScratch(updatedScratch) + } + }) + }, []) // eslint-disable-line react-hooks/exhaustive-deps + return <>
diff --git a/frontend/src/app/scratch/[slug]/page.tsx b/frontend/src/app/scratch/[slug]/page.tsx index 92f25f08..d127e518 100644 --- a/frontend/src/app/scratch/[slug]/page.tsx +++ b/frontend/src/app/scratch/[slug]/page.tsx @@ -1,9 +1,6 @@ import getScratchDetails from "./getScratchDetails" import ScratchEditor from "./ScratchEditor" -// Always server side render, avoiding caching scratch details -export const dynamic = "force-dynamic" - export default async function Page({ params }: { params: { slug: string }}) { const { scratch, parentScratch, compilation } = await getScratchDetails(params.slug) diff --git a/frontend/src/components/Scratch/Scratch.tsx b/frontend/src/components/Scratch/Scratch.tsx index 9fd593ce..34ac12db 100644 --- a/frontend/src/components/Scratch/Scratch.tsx +++ b/frontend/src/components/Scratch/Scratch.tsx @@ -158,10 +158,10 @@ export default function Scratch({ } }, [decompilationTabEnabled]) - // If the slug changes, refresh code editors + // If the version of the scratch changes, refresh code editors useEffect(() => { incrementValueVersion() - }, [scratch.slug]) + }, [scratch.slug, scratch.last_updated]) const renderTab = (id: string) => { switch (id as TabId) { diff --git a/frontend/src/lib/api/request.ts b/frontend/src/lib/api/request.ts index 5d42c08f..c5eccb0d 100644 --- a/frontend/src/lib/api/request.ts +++ b/frontend/src/lib/api/request.ts @@ -43,6 +43,8 @@ export function normalizeUrl(url: string) { export async function get(url: string) { url = normalizeUrl(url) + console.info("GET", url) + const response = await fetch(url, { ...commonOpts, cache: "no-cache",