Skip to content

Instantly share code, notes, and snippets.

@scorsi
Created February 27, 2020 15:03
Show Gist options
  • Save scorsi/2255be4b2cfef007c288d35a25721e08 to your computer and use it in GitHub Desktop.
Save scorsi/2255be4b2cfef007c288d35a25721e08 to your computer and use it in GitHub Desktop.

Revisions

  1. scorsi revised this gist Feb 27, 2020. No changes.
  2. scorsi created this gist Feb 27, 2020.
    92 changes: 92 additions & 0 deletions Router.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,92 @@
    import React, {
    createContext,
    useEffect,
    useState,
    useContext,
    useMemo,
    useCallback
    } from "react";
    import history from "browser-history";
    import pathToRegexp from "path-to-regexp";

    const RouterContext = createContext();

    const Router = ({ children }) => {
    const [url, setUrl] = useState(window.location.pathname);

    useEffect(() => {
    history((e, url) => setUrl(url));
    }, []);

    const go = url => {
    setUrl(url);
    history(url);
    };

    const testUrl = useCallback(
    (path, exact) => {
    const re = pathToRegexp(exact ? path : path + "(.*)", [], {
    sensitive: false
    });
    return {
    doesMatch: re.test(url),
    parts: re.exec(url)
    };
    },
    [url]
    );

    const contextValue = {
    url,
    testUrl,
    go
    };

    return (
    <RouterContext.Provider value={contextValue}>
    {children}
    </RouterContext.Provider>
    );
    };

    const Route = ({
    path,
    exact,
    component: Component,
    children,
    ...componentProps
    }) => {
    const { testUrl } = useContext(RouterContext);
    const r = useMemo(() => testUrl(path, exact), [testUrl, path, exact]);

    if (r.doesMatch) {
    return Component ? (
    <Component {...componentProps} parts={r.parts} />
    ) : (
    children
    );
    }
    return null;
    };

    const Link = ({ path, children }) => {
    const { go } = useContext(RouterContext);

    const onClick = () => {
    go(path);
    };

    return <a onClick={onClick}>{children}</a>;
    };

    const Redirect = ({ from, to }) => {
    const { go, testUrl } = useContext(RouterContext);
    const r = useMemo(() => testUrl(from, true), [testUrl, from]);

    if (r.doesMatch) {
    go(to);
    }
    return null;
    };

    export { RouterContext, Router, Route, Redirect, Link };