Skip to content

Commit

Permalink
lazy hydrate menu
Browse files Browse the repository at this point in the history
  • Loading branch information
Jessevdpoel committed Dec 5, 2023
1 parent 55a93a0 commit 24bcfbe
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 16 deletions.
12 changes: 11 additions & 1 deletion examples/magento-graphcms/components/Layout/LayoutNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ import {
NavigationOverlay,
useNavigationSelection,
useMemoDeep,
LazyHydrate,
} from '@graphcommerce/next-ui'
import { i18n } from '@lingui/core'
import { Trans } from '@lingui/react'
import { Divider, Fab } from '@mui/material'
import { useRouter } from 'next/router'
import { useState } from 'react'
import { Footer } from './Footer'
import { LayoutQuery } from './Layout.gql'
import { Logo } from './Logo'
Expand All @@ -39,9 +41,12 @@ export function LayoutNavigation(props: LayoutNavigationProps) {
const selection = useNavigationSelection()
const router = useRouter()

const [hold, setHold] = useState(true)
const i = () => selection.set([menu?.items?.[0]?.uid || ''])
return (
<>
<NavigationProvider
hold={hold}
selection={selection}
items={useMemoDeep(
() => [
Expand Down Expand Up @@ -126,7 +131,12 @@ export function LayoutNavigation(props: LayoutNavigationProps) {
</DesktopNavItem>
))}

<DesktopNavItem onClick={() => selection.set([menu?.items?.[0]?.uid || ''])}>
<DesktopNavItem
onClick={() => {
setHold(false)
setTimeout(() => selection.set([menu?.items?.[0]?.uid || '']), 100)
}}
>
{menu?.items?.[0]?.name}
<IconSvg src={iconChevronDown} />
</DesktopNavItem>
Expand Down
31 changes: 23 additions & 8 deletions packages/next-ui/LazyHydrate/LazyHydrate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type WithHydrationOnDemandOptions = {
wrapperProps?: React.ComponentProps<'div'>
forceHydration?: boolean
hold?: boolean
afterHydrate?: () => void
}

function withHydrationOnDemandServerSide<P extends object>(options: WithHydrationOnDemandOptions) {
Expand All @@ -26,8 +27,10 @@ function withHydrationOnDemandClientSide<P extends object>(incoming: WithHydrati
const { wrapperProps, forceHydration = false } = incoming

return (Component: React.ComponentType<P>) => {
function ComponentWithHydration(props: P & { forceHydration?: boolean; hold?: boolean }) {
const { hold } = props
function ComponentWithHydration(
props: P & { forceHydration?: boolean; hold?: boolean; afterHydrate?: () => void },
) {
const { hold, afterHydrate } = props
const rootRef = useRef<HTMLElement>(null)

const isInputPending = () => {
Expand All @@ -44,8 +47,11 @@ function withHydrationOnDemandClientSide<P extends object>(incoming: WithHydrati
const [isHydrated, setIsHydrated] = useState(getDefaultHydrationState())

const hydrate = useCallback(() => {
startTransition(() => setIsHydrated(true))
}, [])
startTransition(() => {
setIsHydrated(true)
if (afterHydrate) afterHydrate()
})
}, [afterHydrate])

useLayoutEffect(() => {
if (hold) return
Expand Down Expand Up @@ -116,12 +122,21 @@ export type LazyHydrateProps = {
* When eager is set to true, it disables all functionality and render the component regularly
*/
eager?: boolean

/**
* When hold is set to true, render nothing
*/
hold?: boolean

afterHydrate?: () => void
}

export function LazyHydrate(props: { children: React.ReactNode; eager?: boolean; hold?: boolean }) {
const { children, eager = false, hold = false } = props
export function LazyHydrate(props: {
children: React.ReactNode
eager?: boolean
hold?: boolean
afterHydrate?: () => void
}) {
const { children, eager = false, hold = false, afterHydrate } = props
const LazyComponent = lazyHydrate(() => children)
return eager ? children : <LazyComponent hold={hold} />
return eager ? children : <LazyComponent hold={hold} afterHydrate={afterHydrate} />
}
24 changes: 17 additions & 7 deletions packages/next-ui/Navigation/components/NavigationProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
NavigationNodeComponent,
} from '../hooks/useNavigation'

export type NavigationProviderProps = {
export type NavigationProviderBaseProps = {
items: (NavigationNode | React.ReactElement)[]
hideRootOnNavigate?: boolean
closeAfterNavigate?: boolean
Expand All @@ -21,9 +21,10 @@ export type NavigationProviderProps = {
serverRenderDepth?: number
}

export type NavigationProviderProps = NavigationProviderBaseProps & { hold?: boolean }
const nonNullable = <T,>(value: T): value is NonNullable<T> => value !== null && value !== undefined

export const NavigationProvider = React.memo<NavigationProviderProps>((props) => {
const NavigationProviderBase = React.memo<NavigationProviderBaseProps>((props) => {
const {
items,
hideRootOnNavigate = true,
Expand All @@ -37,6 +38,8 @@ export const NavigationProvider = React.memo<NavigationProviderProps>((props) =>
const animating = useMotionValue(false)
const closing = useMotionValue(false)

console.log('joe')

const value = useMemo<NavigationContextType>(
() => ({
hideRootOnNavigate,
Expand Down Expand Up @@ -69,10 +72,17 @@ export const NavigationProvider = React.memo<NavigationProviderProps>((props) =>
)

return (
<LazyHydrate>
<MotionConfig transition={{ duration: animationDuration }}>
<NavigationContext.Provider value={value}>{children}</NavigationContext.Provider>
</MotionConfig>
</LazyHydrate>
<MotionConfig transition={{ duration: animationDuration }}>
<NavigationContext.Provider value={value}>{children}</NavigationContext.Provider>
</MotionConfig>
)
})

export function NavigationProvider(props: NavigationProviderProps) {
const { hold = false } = props
return (
<LazyHydrate hold={hold} afterHydrate={}>
<NavigationProviderBase {...props} />
</LazyHydrate>
)
}

0 comments on commit 24bcfbe

Please sign in to comment.