fix(ui): infinite loading states when adding blocks or array rows (#10175)
Fixes #10070. Adding new blocks or array rows can randomly get stuck within an infinite loading state. This was because the abort controllers responsible for disregarding duplicate `onChange` and `onSave` events was not properly resetting its refs across invocations. This caused subsequent event handlers to incorrectly abort themselves, leading to unresolved requests and a `null` form state. Similarly, the cleanup effects responsible for aborting these requests on component unmount were also referencing its `current` property directly off the refs, which can possible be stale if not first set as a variable outside the return function. This PR also carries over some missing `onSave` logic from the default edit view into the live preview view. In the future the logic between these two views should be standardized, as they're nearly identical but often become out of sync. This can likely be done through the use of reusable hooks, such as `useOnSave`, `useOnChange`, etc. Same with the document locking functionality which is complex and deeply integrated into each of these views.
This commit is contained in:
@@ -17,7 +17,7 @@ import { useEditDepth } from '../../../providers/EditDepth/index.js'
|
||||
import { OperationProvider } from '../../../providers/Operation/index.js'
|
||||
import { useServerFunctions } from '../../../providers/ServerFunctions/index.js'
|
||||
import { useUploadEdits } from '../../../providers/UploadEdits/index.js'
|
||||
import { abortAndIgnore } from '../../../utilities/abortAndIgnore.js'
|
||||
import { abortAndIgnore, handleAbortRef } from '../../../utilities/abortAndIgnore.js'
|
||||
import { formatAdminURL } from '../../../utilities/formatAdminURL.js'
|
||||
import { useDocumentDrawerContext } from '../../DocumentDrawer/Provider.js'
|
||||
import { DocumentFields } from '../../DocumentFields/index.js'
|
||||
@@ -56,7 +56,7 @@ export function EditForm({ submitted }: EditFormProps) {
|
||||
getEntityConfig,
|
||||
} = useConfig()
|
||||
|
||||
const formStateAbortControllerRef = React.useRef<AbortController>(null)
|
||||
const abortOnChangeRef = React.useRef<AbortController>(null)
|
||||
|
||||
const collectionConfig = getEntityConfig({ collectionSlug: docSlug }) as ClientCollectionConfig
|
||||
const router = useRouter()
|
||||
@@ -111,12 +111,10 @@ export function EditForm({ submitted }: EditFormProps) {
|
||||
|
||||
const onChange: NonNullable<FormProps['onChange']>[0] = useCallback(
|
||||
async ({ formState: prevFormState }) => {
|
||||
abortAndIgnore(formStateAbortControllerRef.current)
|
||||
|
||||
const controller = new AbortController()
|
||||
formStateAbortControllerRef.current = controller
|
||||
const controller = handleAbortRef(abortOnChangeRef)
|
||||
|
||||
const docPreferences = await getDocPreferences()
|
||||
|
||||
const { state: newFormState } = await getFormState({
|
||||
collectionSlug,
|
||||
docPermissions,
|
||||
@@ -127,14 +125,18 @@ export function EditForm({ submitted }: EditFormProps) {
|
||||
signal: controller.signal,
|
||||
})
|
||||
|
||||
abortOnChangeRef.current = null
|
||||
|
||||
return newFormState
|
||||
},
|
||||
[collectionSlug, schemaPath, getDocPreferences, getFormState, docPermissions],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const abortOnChange = abortOnChangeRef.current
|
||||
|
||||
return () => {
|
||||
abortAndIgnore(formStateAbortControllerRef.current)
|
||||
abortAndIgnore(abortOnChange)
|
||||
}
|
||||
}, [])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user