🔖
50行で作るSPA & Global state
History APIやuseSyncExternalStoreを勉強する目的で、SPAとGlobal stateを自作した
History APIのstateにグローバルステートを保存するため、ブラウザバックなどをしてもステートが保持される
state.ts
import { MouseEventHandler, useSyncExternalStore } from "react";
export const useGlobalState = () =>
useSyncExternalStore(subscribeState, getGlobalStateSnapshot);
export const useSearch = () =>
useSyncExternalStore(subscribeState, getSearchSnapshot);
export const handleLink: MouseEventHandler<HTMLAnchorElement> = (event) => {
event.preventDefault();
pushURL(event.currentTarget.href);
};
export const pushURL = (url: string) => {
history.pushState(history.state, "", url);
eventTarget.dispatchEvent(new CustomEvent("change"));
};
export const replaceGlobalState = (
setGlobalStateAction: (
prevGlobalState: GlobalState | null
) => GlobalState | null
) => {
history.replaceState(setGlobalStateAction(history.state), "");
eventTarget.dispatchEvent(new CustomEvent("change"));
};
const eventTarget = new EventTarget();
addEventListener("popstate", () => {
eventTarget.dispatchEvent(new CustomEvent("change"));
});
const subscribeState = (callback: () => void) => {
const handleChange = () => {
callback();
};
eventTarget.addEventListener("change", handleChange);
return () => {
eventTarget.removeEventListener("change", handleChange);
};
};
const getGlobalStateSnapshot = (): GlobalState | null => history.state;
const getSearchSnapshot = () => location.search;
globalState.d.ts
interface GlobalState {
/* ここにグローバルステートの型定義を書いていく */
}
写真地図という個人開発アプリをこれで動かしてる
Discussion