diff options
Diffstat (limited to 'preact/demo/suspense-router')
-rw-r--r-- | preact/demo/suspense-router/bye.js | 12 | ||||
-rw-r--r-- | preact/demo/suspense-router/hello.js | 12 | ||||
-rw-r--r-- | preact/demo/suspense-router/index.js | 30 | ||||
-rw-r--r-- | preact/demo/suspense-router/simple-router.js | 87 |
4 files changed, 141 insertions, 0 deletions
diff --git a/preact/demo/suspense-router/bye.js b/preact/demo/suspense-router/bye.js new file mode 100644 index 0000000..fe2a49c --- /dev/null +++ b/preact/demo/suspense-router/bye.js @@ -0,0 +1,12 @@ +import { createElement } from 'react'; +import { Link } from './simple-router'; + +/** @jsx createElement */ + +export default function Bye() { + return ( + <div> + Bye! <Link to="/">Go to Hello!</Link> + </div> + ); +} diff --git a/preact/demo/suspense-router/hello.js b/preact/demo/suspense-router/hello.js new file mode 100644 index 0000000..2566dd3 --- /dev/null +++ b/preact/demo/suspense-router/hello.js @@ -0,0 +1,12 @@ +import { createElement } from 'react'; +import { Link } from './simple-router'; + +/** @jsx createElement */ + +export default function Hello() { + return ( + <div> + Hello! <Link to="/bye">Go to Bye!</Link> + </div> + ); +} diff --git a/preact/demo/suspense-router/index.js b/preact/demo/suspense-router/index.js new file mode 100644 index 0000000..2572209 --- /dev/null +++ b/preact/demo/suspense-router/index.js @@ -0,0 +1,30 @@ +import { createElement, Suspense, lazy } from 'react'; + +import { Router, Route, Switch } from './simple-router'; + +/** @jsx createElement */ + +let Hello = lazy(() => import('./hello.js')); +let Bye = lazy(() => import('./bye.js')); + +function Loading() { + return <div>Hey! This is a fallback because we're loading things! :D</div>; +} + +export default function SuspenseRouterBug() { + return ( + <Router> + <h1>Suspense Router bug</h1> + <Suspense fallback={<Loading />}> + <Switch> + <Route path="/" exact> + <Hello /> + </Route> + <Route path="/bye"> + <Bye /> + </Route> + </Switch> + </Suspense> + </Router> + ); +} diff --git a/preact/demo/suspense-router/simple-router.js b/preact/demo/suspense-router/simple-router.js new file mode 100644 index 0000000..ed48ea6 --- /dev/null +++ b/preact/demo/suspense-router/simple-router.js @@ -0,0 +1,87 @@ +import { + createElement, + cloneElement, + createContext, + useState, + useContext, + Children, + useLayoutEffect +} from 'react'; + +/** @jsx createElement */ + +const memoryHistory = { + /** + * @typedef {{ pathname: string }} Location + * @typedef {(location: Location) => void} HistoryListener + * @type {HistoryListener[]} + */ + listeners: [], + + /** + * @param {HistoryListener} listener + */ + listen(listener) { + const newLength = this.listeners.push(listener); + return () => this.listeners.splice(newLength - 1, 1); + }, + + /** + * @param {Location} to + */ + navigate(to) { + this.listeners.forEach(listener => listener(to)); + } +}; + +/** @type {import('react').Context<{ history: typeof memoryHistory; location: Location }>} */ +const RouterContext = createContext(null); + +export function Router({ history = memoryHistory, children }) { + const [location, setLocation] = useState({ pathname: '/' }); + + useLayoutEffect(() => { + return history.listen(newLocation => setLocation(newLocation)); + }, []); + + return ( + <RouterContext.Provider value={{ history, location }}> + {children} + </RouterContext.Provider> + ); +} + +export function Switch(props) { + const { location } = useContext(RouterContext); + + let element = null; + Children.forEach(props.children, child => { + if (element == null && child.props.path == location.pathname) { + element = child; + } + }); + + return element; +} + +/** + * @param {{ children: any; path: string; exact?: boolean; }} props + */ +export function Route({ children, path, exact }) { + return children; +} + +export function Link({ to, children }) { + const { history } = useContext(RouterContext); + const onClick = event => { + event.preventDefault(); + event.stopPropagation(); + history.navigate({ pathname: to }); + }; + + return ( + <a href={to} onClick={onClick}> + {children} + </a> + ); +} |