Improve State Management and Location Handling in Dashboard Tabs
- Updated state handling in DashboardTabPanes to ensure null safety for tab state properties. - Introduced a new utility function to determine if a location belongs to a leaving tab, enhancing tab navigation logic. - Refactored location comparison logic to improve accuracy when checking for equality between tab states. - Enhanced NavigationTabsContext to manage same-path query cleanup, improving tab restoration behavior.
This commit is contained in:
parent
d348d6f2b3
commit
4f6f7cb881
@ -24,7 +24,7 @@ const toTabLocation = (tabId, source) => ({
|
||||
pathname: source?.pathname || '/',
|
||||
search: source?.search ?? '',
|
||||
hash: source?.hash ?? '',
|
||||
state: source?.state,
|
||||
state: source?.state ?? null,
|
||||
key: `tab-${tabId}`
|
||||
})
|
||||
|
||||
@ -33,7 +33,7 @@ const reuseTabLocation = (tabId, previous, next) => {
|
||||
previous &&
|
||||
locationsEqual(previous, next) &&
|
||||
previous.key === `tab-${tabId}` &&
|
||||
previous.state === next.state
|
||||
(previous.state ?? null) === (next.state ?? null)
|
||||
) {
|
||||
return previous
|
||||
}
|
||||
@ -45,7 +45,7 @@ const entryToLocation = (entry, fallbackLocation, tabId) =>
|
||||
pathname: entry?.pathname || fallbackLocation.pathname,
|
||||
search: entry?.search ?? fallbackLocation.search ?? '',
|
||||
hash: entry?.hash ?? fallbackLocation.hash ?? '',
|
||||
state: fallbackLocation.state
|
||||
state: entry?.state ?? null
|
||||
})
|
||||
|
||||
const getTabCurrentEntry = (tab) =>
|
||||
@ -57,6 +57,12 @@ const tabMatchesLocation = (tab, loc) => {
|
||||
return locationsEqual(entry, loc)
|
||||
}
|
||||
|
||||
const locationBelongsToLeavingTab = (tab, frozen, loc) => {
|
||||
if (!loc) return false
|
||||
if (frozen && locationsEqual(frozen, loc)) return true
|
||||
return tabMatchesLocation(tab, loc)
|
||||
}
|
||||
|
||||
const CachedTabRouteLayout = () => (
|
||||
<TableStateProvider>
|
||||
<Outlet />
|
||||
@ -67,7 +73,7 @@ const areLocationsEqual = (left, right) =>
|
||||
left === right ||
|
||||
(locationsEqual(left, right) &&
|
||||
left?.key === right?.key &&
|
||||
left?.state === right?.state)
|
||||
(left?.state ?? null) === (right?.state ?? null))
|
||||
|
||||
const arePanePropsEqual = (prev, next) =>
|
||||
prev.tabId === next.tabId &&
|
||||
@ -166,14 +172,20 @@ const DashboardTabPanes = () => {
|
||||
const switchedTabs = Boolean(prevActiveId && activeTabId && prevActiveId !== activeTabId)
|
||||
|
||||
if (switchedTabs) {
|
||||
const previousTab = tabs.find((tab) => tab.id === prevActiveId)
|
||||
const previousFrozen = frozenRef.current.get(prevActiveId)
|
||||
const lastLoc = lastLocationRef.current
|
||||
if (locationBelongsToLeavingTab(previousTab, previousFrozen, lastLoc)) {
|
||||
frozenRef.current.set(
|
||||
prevActiveId,
|
||||
reuseTabLocation(
|
||||
reuseTabLocation(prevActiveId, previousFrozen, lastLoc)
|
||||
)
|
||||
} else if (!previousFrozen && previousTab) {
|
||||
frozenRef.current.set(
|
||||
prevActiveId,
|
||||
frozenRef.current.get(prevActiveId),
|
||||
lastLocationRef.current
|
||||
)
|
||||
entryToLocation(getTabCurrentEntry(previousTab), lastLoc, prevActiveId)
|
||||
)
|
||||
}
|
||||
pendingRestoreRef.current = true
|
||||
}
|
||||
|
||||
|
||||
@ -257,6 +257,13 @@ const applyLocationToTab = (tab, entry) => {
|
||||
if (!tab.history?.length) {
|
||||
return { ...tab, history: [entry], historyIndex: 0 }
|
||||
}
|
||||
const currentPath = currentEntry?.pathname || '/'
|
||||
const nextPath = entry.pathname || '/'
|
||||
if (currentPath === nextPath) {
|
||||
const history = [...tab.history]
|
||||
history[tab.historyIndex] = entry
|
||||
return { ...tab, history }
|
||||
}
|
||||
const truncated = tab.history.slice(0, tab.historyIndex + 1)
|
||||
return {
|
||||
...tab,
|
||||
@ -858,12 +865,17 @@ export const NavigationTabsProvider = ({ children }) => {
|
||||
if (entriesEqual(restoring.from, entry)) {
|
||||
return
|
||||
}
|
||||
// Same-path query cleanup on the tab we just opened (action params, etc.)
|
||||
if (entry.pathname === restoring.target?.pathname) {
|
||||
isRestoringRef.current = null
|
||||
} else if (restoring.previousTabId) {
|
||||
// A delayed write from the previous tab (viewId, filters, etc.)
|
||||
if (restoring.previousTabId) {
|
||||
applyEntryToTabId(restoring.previousTabId, entry)
|
||||
if (foreign) foreign.entry = entry
|
||||
}
|
||||
return
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldIgnoreRestoredLocation(entry)) return
|
||||
@ -877,7 +889,13 @@ export const NavigationTabsProvider = ({ children }) => {
|
||||
if (entriesEqual(entry, foreign.entry)) {
|
||||
return
|
||||
}
|
||||
if (entry.pathname === foreign.entry.pathname) {
|
||||
const activeEntry = getTabCurrentEntry(
|
||||
tabsRef.current.find((tab) => tab.id === activeTabIdRef.current)
|
||||
)
|
||||
if (
|
||||
entry.pathname === foreign.entry.pathname &&
|
||||
entry.pathname !== activeEntry?.pathname
|
||||
) {
|
||||
applyEntryToTabId(foreign.tabId, entry)
|
||||
foreign.entry = entry
|
||||
return
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user