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",