Use history.pushState() for internal links.
rodzic
b28a0114b9
commit
a13f989ab3
|
@ -1,4 +1,4 @@
|
|||
import React from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { PageContext, PAGE_QUERY_ARG } from "./page";
|
||||
import { pageNames, Pages, toPageName, DEFAULT_PAGE } from "./pages";
|
||||
|
@ -11,13 +11,41 @@ if (!appEl) {
|
|||
throw new Error(`Unable to find #${APP_ID}!`);
|
||||
}
|
||||
|
||||
function getWindowSearch(): URLSearchParams {
|
||||
return new URLSearchParams(window.location.search);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the given handler whenever a `popstate` event
|
||||
* occurs.
|
||||
*
|
||||
* Return a function that wraps `window.history.pushState()`;
|
||||
* the given handler will be called immediately afterwards.
|
||||
*/
|
||||
function usePushState(onPushOrPopState: () => void) {
|
||||
useEffect(() => {
|
||||
window.addEventListener("popstate", onPushOrPopState);
|
||||
return () => {
|
||||
window.removeEventListener("popstate", onPushOrPopState);
|
||||
};
|
||||
}, [onPushOrPopState]);
|
||||
|
||||
return function pushState(href: string) {
|
||||
window.history.pushState(null, "", href);
|
||||
onPushOrPopState();
|
||||
};
|
||||
}
|
||||
|
||||
const App: React.FC<{}> = (props) => {
|
||||
const page = new URLSearchParams(window.location.search);
|
||||
const currPage = toPageName(page.get(PAGE_QUERY_ARG) || "", DEFAULT_PAGE);
|
||||
const [search, setSearch] = useState(getWindowSearch());
|
||||
const updateSearchFromWindow = () => setSearch(getWindowSearch());
|
||||
const currPage = toPageName(search.get(PAGE_QUERY_ARG) || "", DEFAULT_PAGE);
|
||||
const PageComponent = Pages[currPage];
|
||||
const pushState = usePushState(updateSearchFromWindow);
|
||||
const ctx: PageContext = {
|
||||
currPage,
|
||||
allPages: pageNames,
|
||||
pushState,
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
29
lib/page.tsx
29
lib/page.tsx
|
@ -1,21 +1,42 @@
|
|||
import React, { useContext } from "react";
|
||||
import React, { MouseEvent, useContext } from "react";
|
||||
import type { PageName } from "./pages";
|
||||
|
||||
export type PageContext = {
|
||||
currPage: PageName;
|
||||
allPages: PageName[];
|
||||
pushState: (href: string) => void;
|
||||
};
|
||||
|
||||
export const PageContext = React.createContext<PageContext>({
|
||||
currPage: "vocabulary",
|
||||
allPages: [],
|
||||
pushState: () => {
|
||||
throw new Error("No page context is defined!");
|
||||
},
|
||||
});
|
||||
|
||||
export const PAGE_QUERY_ARG = "p";
|
||||
|
||||
const PageLink: React.FC<{ page: PageName }> = ({ page }) => (
|
||||
<a href={`?${PAGE_QUERY_ARG}=${encodeURIComponent(page)}`}>{page}</a>
|
||||
);
|
||||
function isNormalLinkClick(e: MouseEvent): boolean {
|
||||
return !e.shiftKey && !e.altKey && !e.metaKey && !e.ctrlKey && e.button === 0;
|
||||
}
|
||||
|
||||
const PageLink: React.FC<{ page: PageName }> = ({ page }) => {
|
||||
const href = `?${PAGE_QUERY_ARG}=${encodeURIComponent(page)}`;
|
||||
const { pushState } = useContext(PageContext);
|
||||
const handleClick = (e: MouseEvent) => {
|
||||
if (isNormalLinkClick(e)) {
|
||||
pushState(href);
|
||||
e.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<a href={href} onClick={handleClick}>
|
||||
{page}
|
||||
</a>
|
||||
);
|
||||
};
|
||||
|
||||
const Navbar: React.FC<{}> = (props) => {
|
||||
const pc = useContext(PageContext);
|
||||
|
|
Ładowanie…
Reference in New Issue