
Research
/Security News
Toptalβs GitHub Organization Hijacked: 10 Malicious Packages Published
Threat actors hijacked Toptalβs GitHub org, publishing npm packages with malicious payloads that steal tokens and attempt to wipe victim systems.
react-chicane
Advanced tools
A simple and safe router for React and TypeScript.
yarn add react-chicane
git clone git@github.com:zoontek/react-chicane.git
cd react-chicane/example
yarn install && yarn dev
This library exports a main function: createRouter
. The goal behind this is to enforce listing all your project routes using fancy names in a file and use the strongly typed methods returned.
import { createRouter } from "react-chicane";
const { useRoute } = createRouter({
root: "/",
users: "/users",
user: "/users/:userId",
});
const App = () => {
const route = useRoute(["root", "users", "user"]);
if (!route) {
return <h1>404</h1>;
}
// route object is a discriminated union
switch (route.name) {
case "root":
return <h1>Homepage</h1>;
case "users":
return <h1>Users</h1>;
case "user":
// params are strongly typed
return <h1>User {route.params.userId}</h1>;
}
};
react-chicane
doesn't bother about what's inside your path, your search params or your hash. It only exposes an object, params
.
string
string
string[]
import { createRouter } from "react-chicane";
import { match } from "ts-pattern";
export const { useRoute } = createRouter({
groups: "/groups",
group: "/groups/:groupId?:foo&:bar[]#:baz",
users: "/groups/:groupId/users",
user: "/groups/:groupId/users/:userId",
// it also supports wildcard routes!
usersArea: "/groups/:groupId/users/*",
});
const App = () => {
const route = useRoute(["groups", "group", "users", "user"]);
match(route)
.with({ name: "groups" }, ({ params }) => console.log(params)) // {}
.with({ name: "group" }, ({ params }) => console.log(params)) // { groupId: string, foo?: string, bar?: string[], baz?: string }
.with({ name: "users" }, ({ params }) => console.log(params)) // { groupId: string }
.with({ name: "user" }, ({ params }) => console.log(params)) // { groupId: string, userId: string }
.otherwise(() => <h1>404</h1>);
// β¦
};
Because it's nice to create safe internal URLs, createRouter
also returns createURL
.
import { createRouter } from "react-chicane";
const { createURL } = createRouter({
root: "/",
users: "/users",
user: "/users/:userId",
});
createURL("root"); // -> "/"
createURL("users"); // -> "/users"
createURL("user", { userId: "zoontek" }); // -> "/users/zoontek"
Create a router instance for your whole application.
import { createRouter } from "react-chicane";
const Router = createRouter(
{
root: "/",
users: "/users",
user: "/users/:userId",
},
{
basePath: "/setup/basePath/here", // Will be prepend to all your paths (optional)
blockerMessage: "Are you sure you want to leave this page?", // A default navigation blocker message (optional)
},
);
Router
instance.type Location = {
url: string;
path: string[];
search: Record<string, string | string[]>;
hash?: string;
};
Router.getLocation(); // Location
Navigate to a given route.
Router.navigate("root");
Router.navigate("users");
Router.navigate("user", { userId: "zoontek" });
Same as navigate
, but will replace the current route in the browser history.
Router.replace("root");
Router.replace("users");
Router.replace("user", { userId: "zoontek" });
Go back in browser history.
Router.goBack();
Go forward in browser history.
Router.goForward();
Safely create internal URLs.
Router.createURL("root"); // -> "/"
Router.createURL("users"); // -> "/users"
Router.createURL("user", { userId: "zoontek" }); // -> "/users/zoontek"
Listen and match a bunch of your routes. Awesome with pattern matching.
import { match } from "ts-pattern";
const App = () => {
// The order isn't important, paths are ranked using https://reach.tech/router/ranking
const route = Router.useRoute(["root", "users", "user"]);
return match(route)
.with({ name: "root" }, () => <h1>root</h1>)
.with({ name: "users" }, () => <h1>users</h1>)
.with({ name: "user" }, ({ params: { userId } }) => <h1>user</h1>)
.otherwise(() => <h1>404</h1>);
};
Registers a component as a route container, so that the element receives focus on route change. When using nested routes, the deepest route container is focused.
const App = () => {
const route = Router.useRoute(["root", "users", "user"]);
const containerRef = React.useRef(null);
Router.useRouteFocus({ containerRef, route });
return <div ref={containerRef}>{/* match your route here */}</div>;
};
Listen and match a bunch of your routes. Returns an array of routes, sorted by descending specificity. Useful for route hierarchical representation (e.g. a breadcrumb component).
import { match } from "ts-pattern";
const Breadcrumbs = () => {
const routes = Router.useRoutes(["root", "users", "user"], {
orderBy: "asc", // accepts "asc" or "desc" order (default is "desc")
});
return routes.map((route) =>
match(route)
.with({ name: "root" }, () => "Home")
.with({ name: "users" }, () => "Users")
.with({ name: "user" }, ({ params: { userId } }) => userId)
.otherwise(() => null),
);
};
As this library doesn't provide a single component, we expose this hook to create your own customized Link
.
const Link = ({
children,
to,
replace,
target,
}: {
children?: React.ReactNode;
to: string;
replace?: boolean;
target?: React.HTMLAttributeAnchorTarget;
}) => {
const { active, onClick } = useLink({ href: to, replace, target });
return (
<a
href={to}
onClick={onClick}
target={target}
style={{ fontWeight: active ? 700 : 400 }}
>
{children}
</a>
);
};
// usage
<Link to={Router.createURL("user", { userId: "zoontek" })}>Profile</Link>;
Listen and react on Router.location
changes.
const App = () => {
const location: Location = Router.useLocation();
React.useEffect(() => {
console.log("location changed", location);
}, [location]);
// β¦
};
Block the navigation and ask user for confirmation. Useful to avoid loosing a form state. It accepts a second paramater if you want to override the default blockerMessage
.
const App = () => {
const { formStatus } = useForm(/* β¦ */);
Router.useBlocker(
formStatus === "editing",
"Are you sure you want to stop editing this profile?",
);
// β¦
};
Subscribe to location changes.
const unsubscribe = Router.subscribe((location: Location) => {
// β¦
});
Two methods similar to Router.navigate
and Router.replace
but which accept a string
as unique argument. Useful for escape hatches.
A quick example with a Redirect
component:
const Redirect = ({ to }: { to: string }) => {
const { url } = Router.useLocation();
React.useLayoutEffect(() => {
if (to !== url) {
Router.unsafeReplace(to);
}
}, []);
return null;
};
// usage
<Redirect to={Router.createURL("root")} />;
Reduce routes declaration repetitions by subpath grouping.
import { createRouter, groupRoutes } from "react-chicane";
const Router = createRouter({
root: "/",
user: "/:userName",
...groupRoutes("repository", "/:repositoryName", {
root: "/",
issues: "/issues",
pulls: "/pulls",
actions: "/actions",
// Can be nested indefinitely
...groupRoutes("settings", "/settings", {
root: "/",
collaborators: "/access",
branches: "/branches",
}),
}),
});
Router.createURL("user", { userName: "zoontek" });
Router.createURL("repository.actions", { repositoryName: "valienv" });
Router.createURL("repository.settings.branches", { repositoryName: "valienv" });
Encode and decode url search parameters.
import { decodeSearch, encodeSearch } from "react-chicane";
encodeSearch({ invitation: "542022247745", users: ["frank", "chris"] });
// -> "?invitation=542022247745&users=frank&users=chris"
decodeSearch("?invitation=542022247745&users=frank&users=chris");
// -> { invitation: "542022247745", users: ["frank", "chris"] }
history
and the Link
creation code.FAQs
A simple and safe router for React and TypeScript
The npm package react-chicane receives a total of 0 weekly downloads. As such, react-chicane popularity was classified as not popular.
We found that react-chicane demonstrated a not healthy version release cadence and project activity because the last version was released a year ago.Β It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
/Security News
Threat actors hijacked Toptalβs GitHub org, publishing npm packages with malicious payloads that steal tokens and attempt to wipe victim systems.
Research
/Security News
Socket researchers investigate 4 malicious npm and PyPI packages with 56,000+ downloads that install surveillance malware.
Security News
The ongoing npm phishing campaign escalates as attackers hijack the popular 'is' package, embedding malware in multiple versions.