Created
April 15, 2023 00:24
-
-
Save eiriklv/1e6672c7987a6db47bf37bc604360bbc to your computer and use it in GitHub Desktop.
React router
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { History, Location } from "history"; | |
import { MatchResult } from "path-to-regexp"; | |
import { ReactElement, useContext, useEffect, useState } from "react"; | |
import React from "react"; | |
import { getPathMatch } from "./utils/routing"; | |
export interface RouterContextInterface { | |
history?: History; | |
location?: Location; | |
basePath: string; | |
} | |
export const routerContextDefaultValue: RouterContextInterface = { | |
basePath: '' | |
}; | |
export const RouterContext = React.createContext<RouterContextInterface>( | |
routerContextDefaultValue | |
); | |
export type RouterProps = { | |
history: History; | |
children: ReactElement; | |
basePath?: string; | |
}; | |
export function Router({ history, children, basePath = '' }: RouterProps) { | |
const [location, setCurrentLocation] = useState<Location>(history.location); | |
useEffect(() => { | |
return history.listen(() => { | |
setCurrentLocation(history.location); | |
}); | |
}); | |
return ( | |
<RouterContext.Provider value={{ history, location, basePath }}> | |
{children} | |
</RouterContext.Provider> | |
); | |
} | |
export interface RouteContextInterface { | |
match?: MatchResult; | |
} | |
export const routeContextDefaultValue: RouteContextInterface = {}; | |
export const RouteContext = React.createContext<RouteContextInterface>( | |
routeContextDefaultValue | |
); | |
export type RouteProps = { | |
path: string; | |
exact?: boolean; | |
children: ReactElement; | |
}; | |
export function Route({ path, exact, children }: RouteProps) { | |
const { location, basePath } = useContext(RouterContext); | |
const pathname = location?.pathname || ""; | |
const pathToMatch = basePath + path; | |
console.log({ pathname, pathToMatch, path }) | |
const pathMatch = getPathMatch(pathToMatch, pathname); | |
const isMatch = exact ? pathToMatch === pathname : !!pathMatch; | |
if (isMatch && pathMatch) { | |
console.log("component route match", pathMatch); | |
return ( | |
<RouteContext.Provider value={{ match: { ...pathMatch, path: pathMatch.path.split(basePath)[1] } }}> | |
{children} | |
</RouteContext.Provider> | |
); | |
} | |
return null; | |
} | |
export type LinkProps = { | |
to: string; | |
children: ReactElement | |
}; | |
export function Link({ to, children }: LinkProps) { | |
const history = useHistory(); | |
const basePath = useBasePath(); | |
const fullPath = basePath + to; | |
const handleClick = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => { | |
event.preventDefault(); | |
history.push(fullPath); | |
} | |
return ( | |
<a href={fullPath} onClick={handleClick}> | |
{children} | |
</a> | |
) | |
} | |
export const useMatch = () => { | |
const { match } = useContext(RouteContext); | |
return match as MatchResult; | |
}; | |
export const useLocation = () => { | |
const { location } = useContext(RouterContext); | |
return location as Location; | |
}; | |
export const useHistory = () => { | |
const { history } = useContext(RouterContext); | |
return history as History; | |
}; | |
export const useBasePath = () => { | |
const { basePath } = useContext(RouterContext); | |
return basePath; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment