Skip to content

Commit 0a6d594

Browse files
committed
add useLoadingEffect
1 parent 4a086f4 commit 0a6d594

File tree

2 files changed

+53
-12
lines changed

2 files changed

+53
-12
lines changed

example/pages/index.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
import { Link, ReloadContext } from "bun-react-ssr/router";
1+
import { Link, ReloadContext, useLoadingEffect } from "bun-react-ssr/router";
22
import { useContext } from "react";
33

44
export default function Index({ time }: { time: Date }) {
55
const reload = useContext(ReloadContext);
6+
useLoadingEffect(() => {
7+
console.log("reload!");
8+
});
69
return (
710
<div>
811
<div>time {time.toISOString()}</div>

router/index.tsx

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import React, {
22
createContext,
3+
startTransition,
34
useCallback,
5+
useContext,
46
useEffect,
57
useRef,
68
useState,
@@ -37,6 +39,29 @@ async function fetchServerSideProps(pathname: string) {
3739
throw new Error("Failed to fetch");
3840
}
3941

42+
const VersionContext = createContext(0);
43+
44+
/**
45+
* a hook that returns a version number that is incremented on each route change or reload
46+
* @returns the current version (incremented on each route change or reload)
47+
*/
48+
export const useLoadingVersion = () => useContext(VersionContext);
49+
50+
/**
51+
* a hook that runs an effect when the version changes, which is incremented on each route change or reload
52+
* @param effect the effect to run
53+
* @param deps the dependencies
54+
*/
55+
export const useLoadingEffect = (
56+
effect: React.EffectCallback,
57+
deps: React.DependencyList = []
58+
) => {
59+
useEffect(effect, [useContext(VersionContext), ...deps]);
60+
};
61+
62+
/**
63+
* a context that can be used to reload the current page
64+
*/
4065
export const ReloadContext = createContext(async (): Promise<void> => {});
4166

4267
export const RouterHost = ({
@@ -66,27 +91,31 @@ export const RouterHost = ({
6691
if (props?.redirect) {
6792
navigate(props.redirect);
6893
} else {
69-
onRouteUpdated?.(target);
70-
setCurrent(
71-
<Shell {...props}>
72-
<module.default {...props?.props} />
73-
</Shell>
74-
);
94+
startTransition(() => {
95+
onRouteUpdated?.(target);
96+
setCurrent(
97+
<VersionContext.Provider value={currentVersion}>
98+
<Shell {...props}>
99+
<module.default {...props?.props} />
100+
</Shell>
101+
</VersionContext.Provider>
102+
);
103+
});
75104
}
76105
}
77106
},
78107
[]
79108
);
80109
useEffect(() => {
81-
if (pathname !== globalX.__INITIAL_ROUTE__) {
110+
if (pathname === globalX.__INITIAL_ROUTE__) {
111+
onRouteUpdated?.(pathname);
112+
// @ts-ignore
113+
delete globalX.__INITIAL_ROUTE__;
114+
} else {
82115
reload(pathname).catch((e) => {
83116
console.log(e);
84117
location.href = pathname;
85118
});
86-
} else {
87-
onRouteUpdated?.(pathname);
88-
// @ts-ignore
89-
delete globalX.__INITIAL_ROUTE__;
90119
}
91120
}, [pathname]);
92121
return (
@@ -112,13 +141,22 @@ export function useLocationProperty<S extends Location[keyof Location]>(
112141
return useSyncExternalStore(subscribeToLocationUpdates, fn, ssrFn);
113142
}
114143

144+
/**
145+
* a hook that returns the current pathname
146+
* @returns the current pathname
147+
*/
115148
export function usePathname() {
116149
return useLocationProperty(
117150
() => location.pathname,
118151
() => globalX.__INITIAL_ROUTE__
119152
);
120153
}
121154

155+
/**
156+
* a function that navigates/replaces to a path
157+
* @param to the path to navigate to
158+
* @param param1 the options, which can include `replace`
159+
*/
122160
export const navigate = (to: string, { replace = false } = {}) =>
123161
history[replace ? eventReplaceState : eventPushState](null, "", to);
124162

0 commit comments

Comments
 (0)