Skip to content

Commit edd34fa

Browse files
committed
[dev-overlay] Move Redbox open/close into dispatcher
1 parent f2f5722 commit edd34fa

File tree

10 files changed

+107
-63
lines changed

10 files changed

+107
-63
lines changed

packages/next/src/client/components/react-dev-overlay/app/app-dev-overlay.tsx

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
import type { OverlayState } from '../shared'
1+
import {
2+
ACTION_ERROR_OVERLAY_OPEN,
3+
type OverlayDispatch,
4+
type OverlayState,
5+
} from '../shared'
26
import type { GlobalErrorComponent } from '../../global-error'
37

4-
import { useCallback, useEffect, useState } from 'react'
8+
import { useCallback, useEffect } from 'react'
59
import { AppDevOverlayErrorBoundary } from './app-dev-overlay-error-boundary'
610
import { FontStyles } from '../font/font-styles'
711
import { DevOverlay } from '../ui/dev-overlay'
@@ -70,17 +74,18 @@ function ReplaySsrOnlyErrors({
7074

7175
export function AppDevOverlay({
7276
state,
77+
dispatch,
7378
globalError,
7479
children,
7580
}: {
7681
state: OverlayState
82+
dispatch: OverlayDispatch
7783
globalError: [GlobalErrorComponent, React.ReactNode]
7884
children: React.ReactNode
7985
}) {
80-
const [isErrorOverlayOpen, setIsErrorOverlayOpen] = useState(false)
8186
const openOverlay = useCallback(() => {
82-
setIsErrorOverlayOpen(true)
83-
}, [])
87+
dispatch({ type: ACTION_ERROR_OVERLAY_OPEN })
88+
}, [dispatch])
8489

8590
return (
8691
<>
@@ -94,11 +99,7 @@ export function AppDevOverlay({
9499
<>
95100
{/* Fonts can only be loaded outside the Shadow DOM. */}
96101
<FontStyles />
97-
<DevOverlay
98-
state={state}
99-
isErrorOverlayOpen={isErrorOverlayOpen}
100-
setIsErrorOverlayOpen={setIsErrorOverlayOpen}
101-
/>
102+
<DevOverlay state={state} dispatch={dispatch} />
102103
</>
103104
</>
104105
)

packages/next/src/client/components/react-dev-overlay/app/hot-reloader-client.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ export default function HotReload({
624624
])
625625

626626
return (
627-
<AppDevOverlay state={state} globalError={globalError}>
627+
<AppDevOverlay state={state} dispatch={dispatch} globalError={globalError}>
628628
{children}
629629
</AppDevOverlay>
630630
)

packages/next/src/client/components/react-dev-overlay/pages/hooks.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,6 @@ export const usePagesDevOverlay = () => {
3030
return {
3131
state,
3232
onComponentError,
33+
dispatch,
3334
}
3435
}
Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { useState } from 'react'
21
import { PagesDevOverlayErrorBoundary } from './pages-dev-overlay-error-boundary'
32
import { usePagesDevOverlay } from './hooks'
43
import { FontStyles } from '../font/font-styles'
@@ -13,9 +12,7 @@ interface PagesDevOverlayProps {
1312
}
1413

1514
export function PagesDevOverlay({ children }: PagesDevOverlayProps) {
16-
const { state, onComponentError } = usePagesDevOverlay()
17-
18-
const [isErrorOverlayOpen, setIsErrorOverlayOpen] = useState(true)
15+
const { state, dispatch, onComponentError } = usePagesDevOverlay()
1916

2017
return (
2118
<>
@@ -25,11 +22,7 @@ export function PagesDevOverlay({ children }: PagesDevOverlayProps) {
2522

2623
{/* Fonts can only be loaded outside the Shadow DOM. */}
2724
<FontStyles />
28-
<DevOverlay
29-
state={state}
30-
isErrorOverlayOpen={isErrorOverlayOpen}
31-
setIsErrorOverlayOpen={setIsErrorOverlayOpen}
32-
/>
25+
<DevOverlay state={state} dispatch={dispatch} />
3326
</>
3427
)
3528
}

packages/next/src/client/components/react-dev-overlay/shared.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ export interface OverlayState {
2727
disableDevIndicator: boolean
2828
debugInfo: DebugInfo
2929
routerType: 'pages' | 'app'
30+
isErrorOverlayOpen: boolean
3031
}
32+
export type OverlayDispatch = React.Dispatch<BusEvent>
3133

3234
export const ACTION_STATIC_INDICATOR = 'static-indicator'
3335
export const ACTION_BUILD_OK = 'build-ok'
@@ -39,6 +41,9 @@ export const ACTION_UNHANDLED_ERROR = 'unhandled-error'
3941
export const ACTION_UNHANDLED_REJECTION = 'unhandled-rejection'
4042
export const ACTION_DEBUG_INFO = 'debug-info'
4143
export const ACTION_DEV_INDICATOR = 'dev-indicator'
44+
export const ACTION_ERROR_OVERLAY_OPEN = 'error-overlay-open'
45+
export const ACTION_ERROR_OVERLAY_CLOSE = 'error-overlay-close'
46+
export const ACTION_ERROR_OVERLAY_TOGGLE = 'error-overlay-toggle'
4247

4348
export const STORAGE_KEY_THEME = '__nextjs-dev-tools-theme'
4449
export const STORAGE_KEY_POSITION = '__nextjs-dev-tools-position'
@@ -90,6 +95,16 @@ interface DevIndicatorAction {
9095
devIndicator: DevIndicatorServerState
9196
}
9297

98+
export interface ErrorOverlayOpenAction {
99+
type: typeof ACTION_ERROR_OVERLAY_OPEN
100+
}
101+
export interface ErrorOverlayCloseAction {
102+
type: typeof ACTION_ERROR_OVERLAY_CLOSE
103+
}
104+
export interface ErrorOverlayToggleAction {
105+
type: typeof ACTION_ERROR_OVERLAY_TOGGLE
106+
}
107+
93108
export type BusEvent =
94109
| BuildOkAction
95110
| BuildErrorAction
@@ -101,6 +116,9 @@ export type BusEvent =
101116
| StaticIndicatorAction
102117
| DebugInfoAction
103118
| DevIndicatorAction
119+
| ErrorOverlayOpenAction
120+
| ErrorOverlayCloseAction
121+
| ErrorOverlayToggleAction
104122

105123
const REACT_ERROR_STACK_BOTTOM_FRAME_REGEX =
106124
// 1st group: v8
@@ -140,6 +158,7 @@ export const INITIAL_OVERLAY_STATE: Omit<OverlayState, 'routerType'> = {
140158
nextId: 1,
141159
buildError: null,
142160
errors: [],
161+
isErrorOverlayOpen: false,
143162
notFound: false,
144163
staticIndicator: false,
145164
/*
@@ -239,6 +258,15 @@ export function useErrorOverlayReducer(routerType: 'pages' | 'app') {
239258
shouldDisableDevIndicator || !!action.devIndicator.disabledUntil,
240259
}
241260
}
261+
case ACTION_ERROR_OVERLAY_OPEN: {
262+
return { ...state, isErrorOverlayOpen: true }
263+
}
264+
case ACTION_ERROR_OVERLAY_CLOSE: {
265+
return { ...state, isErrorOverlayOpen: false }
266+
}
267+
case ACTION_ERROR_OVERLAY_TOGGLE: {
268+
return { ...state, isErrorOverlayOpen: !state.isErrorOverlayOpen }
269+
}
242270
default: {
243271
return state
244272
}

packages/next/src/client/components/react-dev-overlay/ui/components/errors/dev-tools-indicator/dev-tools-indicator.stories.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,14 @@ const state: OverlayState = {
5656
notFound: false,
5757
staticIndicator: true,
5858
debugInfo: { devtoolsFrontendUrl: undefined },
59+
isErrorOverlayOpen: false,
5960
}
6061

6162
export const StaticRoute: Story = {
6263
args: {
6364
errorCount: 0,
6465
state,
65-
setIsErrorOverlayOpen: () => {},
66+
dispatch: () => {},
6667
},
6768
}
6869

@@ -73,22 +74,22 @@ export const DynamicRoute: Story = {
7374
...state,
7475
staticIndicator: false,
7576
},
76-
setIsErrorOverlayOpen: () => {},
77+
dispatch: () => {},
7778
},
7879
}
7980

8081
export const SingleError: Story = {
8182
args: {
8283
errorCount: 1,
8384
state,
84-
setIsErrorOverlayOpen: () => {},
85+
dispatch: () => {},
8586
},
8687
}
8788

8889
export const MultipleErrors: Story = {
8990
args: {
9091
errorCount: 3,
9192
state,
92-
setIsErrorOverlayOpen: () => {},
93+
dispatch: () => {},
9394
},
9495
}

packages/next/src/client/components/react-dev-overlay/ui/components/errors/dev-tools-indicator/dev-tools-indicator.tsx

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import type { CSSProperties, Dispatch, SetStateAction } from 'react'
2-
import { STORAGE_KEY_POSITION, type OverlayState } from '../../../../shared'
2+
import {
3+
ACTION_ERROR_OVERLAY_OPEN,
4+
ACTION_ERROR_OVERLAY_TOGGLE,
5+
STORAGE_KEY_POSITION,
6+
type OverlayDispatch,
7+
type OverlayState,
8+
} from '../../../../shared'
39

410
import { useState, useEffect, useRef, createContext, useContext } from 'react'
511
import { Toast } from '../../toast'
@@ -30,15 +36,13 @@ export function DevToolsIndicator({
3036
state,
3137
errorCount,
3238
isBuildError,
33-
setIsErrorOverlayOpen,
3439
...props
3540
}: {
3641
state: OverlayState
42+
dispatch: OverlayDispatch
3743
errorCount: number
3844
isBuildError: boolean
39-
setIsErrorOverlayOpen: (
40-
isErrorOverlayOpen: boolean | ((prev: boolean) => boolean)
41-
) => void
45+
4246
scale: DevToolsScale
4347
setScale: (value: DevToolsScale) => void
4448
}) {
@@ -57,7 +61,6 @@ export function DevToolsIndicator({
5761
method: 'POST',
5862
})
5963
}}
60-
setIsErrorOverlayOpen={setIsErrorOverlayOpen}
6164
isTurbopack={!!process.env.TURBOPACK}
6265
disabled={state.disableDevIndicator || !isDevToolsIndicatorVisible}
6366
isBuildError={isBuildError}
@@ -96,7 +99,7 @@ function DevToolsPopover({
9699
isTurbopack,
97100
isBuildError,
98101
hide,
99-
setIsErrorOverlayOpen,
102+
dispatch,
100103
scale,
101104
setScale,
102105
}: {
@@ -108,9 +111,7 @@ function DevToolsPopover({
108111
isTurbopack: boolean
109112
isBuildError: boolean
110113
hide: () => void
111-
setIsErrorOverlayOpen: (
112-
isOverlayOpen: boolean | ((prev: boolean) => boolean)
113-
) => void
114+
dispatch: OverlayDispatch
114115
scale: DevToolsScale
115116
setScale: (value: DevToolsScale) => void
116117
}) {
@@ -210,12 +211,12 @@ function DevToolsPopover({
210211
function openErrorOverlay() {
211212
setOpen(null)
212213
if (issueCount > 0) {
213-
setIsErrorOverlayOpen(true)
214+
dispatch({ type: ACTION_ERROR_OVERLAY_OPEN })
214215
}
215216
}
216217

217218
function toggleErrorOverlay() {
218-
setIsErrorOverlayOpen((prev) => !prev)
219+
dispatch({ type: ACTION_ERROR_OVERLAY_TOGGLE })
219220
}
220221

221222
function openRootMenu() {

packages/next/src/client/components/react-dev-overlay/ui/components/errors/error-overlay/error-overlay.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import type { OverlayState } from '../../../../shared'
1+
import {
2+
ACTION_ERROR_OVERLAY_CLOSE,
3+
type OverlayDispatch,
4+
type OverlayState,
5+
} from '../../../../shared'
26

37
import { Suspense } from 'react'
48
import { BuildError } from '../../../container/build-error'
@@ -18,21 +22,19 @@ export interface ErrorBaseProps {
1822

1923
export function ErrorOverlay({
2024
state,
25+
dispatch,
2126
runtimeErrors,
22-
isErrorOverlayOpen,
23-
setIsErrorOverlayOpen,
2427
errorCount,
2528
}: {
2629
state: OverlayState
30+
dispatch: OverlayDispatch
2731
runtimeErrors: ReadyRuntimeError[]
28-
isErrorOverlayOpen: boolean
29-
setIsErrorOverlayOpen: (value: boolean) => void
3032
errorCount: number
3133
}) {
3234
const isTurbopack = !!process.env.TURBOPACK
3335

3436
// This hook lets us do an exit animation before unmounting the component
35-
const { mounted, rendered } = useDelayedRender(isErrorOverlayOpen, {
37+
const { mounted, rendered } = useDelayedRender(state.isErrorOverlayOpen, {
3638
exitDelay: transitionDurationMs,
3739
})
3840

@@ -74,7 +76,7 @@ export function ErrorOverlay({
7476
debugInfo={state.debugInfo}
7577
runtimeErrors={runtimeErrors}
7678
onClose={() => {
77-
setIsErrorOverlayOpen(false)
79+
dispatch({ type: ACTION_ERROR_OVERLAY_CLOSE })
7880
}}
7981
/>
8082
)

0 commit comments

Comments
 (0)