Skip to content

Commit 1fd8de3

Browse files
committed
Convert to Function Component
1 parent 7035d6f commit 1fd8de3

File tree

1 file changed

+57
-64
lines changed

1 file changed

+57
-64
lines changed

packages/next/src/client/components/layout-router.tsx

Lines changed: 57 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import React, {
2222
startTransition,
2323
Suspense,
2424
useDeferredValue,
25+
useLayoutEffect,
2526
type FragmentInstance,
2627
type JSX,
2728
} from 'react'
@@ -307,81 +308,73 @@ class InnerScrollAndFocusHandlerOld extends React.Component<ScrollAndFocusHandle
307308
}
308309
}
309310

310-
class InnerScrollAndFocusHandlerNew extends React.Component<ScrollAndFocusHandlerProps> {
311-
childrenRef = React.createRef<FragmentInstance>()
312-
313-
handlePotentialScroll = () => {
314-
// Handle scroll and focus, it's only applied once in the first useEffect that triggers that changed.
315-
const { focusAndScrollRef, segmentPath } = this.props
316-
317-
if (focusAndScrollRef.apply) {
318-
// segmentPaths is an array of segment paths that should be scrolled to
319-
// if the current segment path is not in the array, the scroll is not applied
320-
// unless the array is empty, in which case the scroll is always applied
321-
if (
322-
focusAndScrollRef.segmentPaths.length !== 0 &&
323-
!focusAndScrollRef.segmentPaths.some((scrollRefSegmentPath) =>
324-
segmentPath.every((segment, index) =>
325-
matchSegment(segment, scrollRefSegmentPath[index])
311+
function InnerScrollAndFocusHandlerNew(props: ScrollAndFocusHandlerProps) {
312+
const childrenRef = React.useRef<FragmentInstance>(null)
313+
314+
useLayoutEffect(
315+
() => {
316+
const { focusAndScrollRef, segmentPath } = props
317+
// Handle scroll and focus, it's only applied once in the first useEffect that triggers that changed.
318+
319+
if (focusAndScrollRef.apply) {
320+
// segmentPaths is an array of segment paths that should be scrolled to
321+
// if the current segment path is not in the array, the scroll is not applied
322+
// unless the array is empty, in which case the scroll is always applied
323+
if (
324+
focusAndScrollRef.segmentPaths.length !== 0 &&
325+
!focusAndScrollRef.segmentPaths.some((scrollRefSegmentPath) =>
326+
segmentPath.every((segment, index) =>
327+
matchSegment(segment, scrollRefSegmentPath[index])
328+
)
326329
)
327-
)
328-
) {
329-
return
330-
}
331-
332-
let domNode: FragmentInstance | HTMLElement | null = null
333-
const hashFragment = focusAndScrollRef.hashFragment
334-
335-
if (hashFragment) {
336-
domNode = getHashFragmentDomNode(hashFragment)
337-
}
330+
) {
331+
return
332+
}
338333

339-
if (!domNode) {
340-
domNode = this.childrenRef.current
341-
}
334+
let domNode: FragmentInstance | HTMLElement | null = null
335+
const hashFragment = focusAndScrollRef.hashFragment
342336

343-
// If there is no DOM node this layout-router level is skipped. It'll be handled higher-up in the tree.
344-
if (domNode === null) {
345-
return
346-
}
337+
if (hashFragment) {
338+
domNode = getHashFragmentDomNode(hashFragment)
339+
}
347340

348-
// State is mutated to ensure that the focus and scroll is applied only once.
349-
focusAndScrollRef.apply = false
350-
focusAndScrollRef.hashFragment = null
351-
focusAndScrollRef.segmentPaths = []
341+
if (!domNode) {
342+
domNode = childrenRef.current
343+
}
352344

353-
const alignToTop = false
354-
disableSmoothScrollDuringRouteTransition(
355-
domNode.experimental_scrollIntoView.bind(domNode, alignToTop),
356-
{
357-
// We will force layout by querying domNode position
358-
dontForceLayout: true,
359-
onlyHashChange: focusAndScrollRef.onlyHashChange,
345+
// If there is no DOM node this layout-router level is skipped. It'll be handled higher-up in the tree.
346+
if (domNode === null) {
347+
return
360348
}
361-
)
362349

363-
// Mutate after scrolling so that it can be read by `disableSmoothScrollDuringRouteTransition`
364-
focusAndScrollRef.onlyHashChange = false
350+
// State is mutated to ensure that the focus and scroll is applied only once.
351+
focusAndScrollRef.apply = false
352+
focusAndScrollRef.hashFragment = null
353+
focusAndScrollRef.segmentPaths = []
365354

366-
// Set focus on the element
367-
domNode.focus()
368-
}
369-
}
355+
const alignToTop = false
356+
disableSmoothScrollDuringRouteTransition(
357+
domNode.experimental_scrollIntoView.bind(domNode, alignToTop),
358+
{
359+
// We will force layout by querying domNode position
360+
dontForceLayout: true,
361+
onlyHashChange: focusAndScrollRef.onlyHashChange,
362+
}
363+
)
370364

371-
componentDidMount() {
372-
this.handlePotentialScroll()
373-
}
365+
// Mutate after scrolling so that it can be read by `disableSmoothScrollDuringRouteTransition`
366+
focusAndScrollRef.onlyHashChange = false
374367

375-
componentDidUpdate() {
376-
// Because this property is overwritten in handlePotentialScroll it's fine to always run it when true as it'll be set to false for subsequent renders.
377-
if (this.props.focusAndScrollRef.apply) {
378-
this.handlePotentialScroll()
379-
}
380-
}
368+
// Set focus on the element
369+
domNode.focus()
370+
}
371+
},
372+
// Used to run on every commit. We may be able to be smarter about this
373+
// but be prepared for lots of manual testing.
374+
undefined
375+
)
381376

382-
render() {
383-
return <Fragment ref={this.childrenRef}>{this.props.children}</Fragment>
384-
}
377+
return <Fragment ref={childrenRef}>{props.children}</Fragment>
385378
}
386379

387380
const InnerScrollAndFocusHandler = enableNewScrollHandler

0 commit comments

Comments
 (0)