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 || '/',
|
pathname: source?.pathname || '/',
|
||||||
search: source?.search ?? '',
|
search: source?.search ?? '',
|
||||||
hash: source?.hash ?? '',
|
hash: source?.hash ?? '',
|
||||||
state: source?.state,
|
state: source?.state ?? null,
|
||||||
key: `tab-${tabId}`
|
key: `tab-${tabId}`
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ const reuseTabLocation = (tabId, previous, next) => {
|
|||||||
previous &&
|
previous &&
|
||||||
locationsEqual(previous, next) &&
|
locationsEqual(previous, next) &&
|
||||||
previous.key === `tab-${tabId}` &&
|
previous.key === `tab-${tabId}` &&
|
||||||
previous.state === next.state
|
(previous.state ?? null) === (next.state ?? null)
|
||||||
) {
|
) {
|
||||||
return previous
|
return previous
|
||||||
}
|
}
|
||||||
@ -45,7 +45,7 @@ const entryToLocation = (entry, fallbackLocation, tabId) =>
|
|||||||
pathname: entry?.pathname || fallbackLocation.pathname,
|
pathname: entry?.pathname || fallbackLocation.pathname,
|
||||||
search: entry?.search ?? fallbackLocation.search ?? '',
|
search: entry?.search ?? fallbackLocation.search ?? '',
|
||||||
hash: entry?.hash ?? fallbackLocation.hash ?? '',
|
hash: entry?.hash ?? fallbackLocation.hash ?? '',
|
||||||
state: fallbackLocation.state
|
state: entry?.state ?? null
|
||||||
})
|
})
|
||||||
|
|
||||||
const getTabCurrentEntry = (tab) =>
|
const getTabCurrentEntry = (tab) =>
|
||||||
@ -57,6 +57,12 @@ const tabMatchesLocation = (tab, loc) => {
|
|||||||
return locationsEqual(entry, 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 = () => (
|
const CachedTabRouteLayout = () => (
|
||||||
<TableStateProvider>
|
<TableStateProvider>
|
||||||
<Outlet />
|
<Outlet />
|
||||||
@ -67,7 +73,7 @@ const areLocationsEqual = (left, right) =>
|
|||||||
left === right ||
|
left === right ||
|
||||||
(locationsEqual(left, right) &&
|
(locationsEqual(left, right) &&
|
||||||
left?.key === right?.key &&
|
left?.key === right?.key &&
|
||||||
left?.state === right?.state)
|
(left?.state ?? null) === (right?.state ?? null))
|
||||||
|
|
||||||
const arePanePropsEqual = (prev, next) =>
|
const arePanePropsEqual = (prev, next) =>
|
||||||
prev.tabId === next.tabId &&
|
prev.tabId === next.tabId &&
|
||||||
@ -166,14 +172,20 @@ const DashboardTabPanes = () => {
|
|||||||
const switchedTabs = Boolean(prevActiveId && activeTabId && prevActiveId !== activeTabId)
|
const switchedTabs = Boolean(prevActiveId && activeTabId && prevActiveId !== activeTabId)
|
||||||
|
|
||||||
if (switchedTabs) {
|
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(
|
frozenRef.current.set(
|
||||||
prevActiveId,
|
prevActiveId,
|
||||||
reuseTabLocation(
|
reuseTabLocation(prevActiveId, previousFrozen, lastLoc)
|
||||||
|
)
|
||||||
|
} else if (!previousFrozen && previousTab) {
|
||||||
|
frozenRef.current.set(
|
||||||
prevActiveId,
|
prevActiveId,
|
||||||
frozenRef.current.get(prevActiveId),
|
entryToLocation(getTabCurrentEntry(previousTab), lastLoc, prevActiveId)
|
||||||
lastLocationRef.current
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
}
|
||||||
pendingRestoreRef.current = true
|
pendingRestoreRef.current = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -257,6 +257,13 @@ const applyLocationToTab = (tab, entry) => {
|
|||||||
if (!tab.history?.length) {
|
if (!tab.history?.length) {
|
||||||
return { ...tab, history: [entry], historyIndex: 0 }
|
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)
|
const truncated = tab.history.slice(0, tab.historyIndex + 1)
|
||||||
return {
|
return {
|
||||||
...tab,
|
...tab,
|
||||||
@ -858,12 +865,17 @@ export const NavigationTabsProvider = ({ children }) => {
|
|||||||
if (entriesEqual(restoring.from, entry)) {
|
if (entriesEqual(restoring.from, entry)) {
|
||||||
return
|
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.)
|
// A delayed write from the previous tab (viewId, filters, etc.)
|
||||||
if (restoring.previousTabId) {
|
|
||||||
applyEntryToTabId(restoring.previousTabId, entry)
|
applyEntryToTabId(restoring.previousTabId, entry)
|
||||||
if (foreign) foreign.entry = entry
|
if (foreign) foreign.entry = entry
|
||||||
}
|
|
||||||
return
|
return
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldIgnoreRestoredLocation(entry)) return
|
if (shouldIgnoreRestoredLocation(entry)) return
|
||||||
@ -877,7 +889,13 @@ export const NavigationTabsProvider = ({ children }) => {
|
|||||||
if (entriesEqual(entry, foreign.entry)) {
|
if (entriesEqual(entry, foreign.entry)) {
|
||||||
return
|
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)
|
applyEntryToTabId(foreign.tabId, entry)
|
||||||
foreign.entry = entry
|
foreign.entry = entry
|
||||||
return
|
return
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user