Skip to content

Instantly share code, notes, and snippets.

@nandorojo
Last active March 16, 2024 11:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save nandorojo/50d7b40e42d35f211d91cfce5227036e to your computer and use it in GitHub Desktop.
Save nandorojo/50d7b40e42d35f211d91cfce5227036e to your computer and use it in GitHub Desktop.
Next.js / Solito canGoBack()

These files are provided as-is. Can't guarantee it works, but please comment with any fixes if it doesn't work correctly.

Using immer is total overkill, I just had it there (I made this years ago). Feel free to remove that if you know what you're doing.

Usage

Add the provider to the root of your app (_app.tsx).

Then, import the useCanGoBack hook anywhere:

export function Screen() {
  const getCanGoBack = useCanGoBack()
  
  const showHeader = getCanGoBack()
  
  if (showHeader) return <Header />
  
  return null
}
// this won't ever get imported on native, but we put this file here to make that clear
export default ({children}) => children
import React, { useEffect, useMemo, useState, createContext } from 'react'
import Router, { useRouter } from 'next/router'
import produce from 'immer'
const RouterContext = createContext<{ canGoBack(): boolean }>({
canGoBack: () => false as boolean,
})
type Props = {
children: React.ReactNode
}
export default function NextRouterProvider(props: Props) {
const { children } = props
const { events, beforePopState } = useRouter()!
const [history, setHistory] = useState<Array<string>>([])
const state = useMemo(
() => ({
canGoBack: () => history.length > 0,
}),
[history]
)
useEffect(() => {
const handleChange = () => {
setHistory((history) => {
if (history[history.length - 1] !== Router.pathname) {
return [...history, Router.pathname]
}
return history
})
}
events.on('routeChangeComplete', handleChange)
const onPopState = ({ url }: { url: string }) => {
setHistory((history) => {
return produce(history, (draft) => {
if (url === draft[draft.length - 1]) {
draft.pop()
}
return draft
})
})
return true
}
beforePopState(onPopState)
return () => {
events.off('routeChangeComplete', handleChange)
}
}, [beforePopState, events])
return (
<RouterContext.Provider value={state}>{children}</RouterContext.Provider>
)
}
import { useNavigation } from '@react-navigation/native'
export default function() {
return useNavigation().canGoBack
}
import { useContext } from 'react'
import RouterContext from './provider.web'
export default function() {
return useContext(RouterContext).canGoBack
}
export { default as useCanGoBack } from './use-can-go-back-impl'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment