Quality of Life Changes
Pre-releaseBreaking Changes!
While Curi is in beta, I still don't love making breaking changes. However, as it gets closer to an "official" release, there are API fixes that I would rather make now than having to wait for v2, etc.
Apologies to anyone who has to do any large rewrites because of this, but I believe that these changes will make Curi much more approachable. I do not foresee any other large changes because this covers all of the nits I had. I am confident that Curi is in a better place because of these changes, and I hope that you agree.
- Breaking up the
matchAPI.
The response() function is now moved to the top-level of a route and every() and initial() are grouped under the on object. on provides a better semantic grouping, especially for any future additions (on.unload()?).
// before
{
match: {
initial() => {...},
every() => {...},
response() => {...}
}
}
// new
{
response() => {...},
on: {
initial() => {...},
every() => {...}
}
}- No more "add-ons"
"Add-on" was always a bit of a strange name for functions to interact with routes because it didn't make their purpose obvious. From now on, these functions will just be called "route interactions".
Route intearctions are accessible through the router's route property e.g. router.route.pathname("Home"). Official route interactions are moved to @curi/route- packages (@curi/route-active, @curi/route-ancestors, and @curi/route-prefetch).
Route interactions are registered with the route option array.
// old
import active from "@curi/addon-active";
const router = curi(history, routes, {
addons: [active()]
});
// new
import active from "@curi/route-active";
const router = curi(history, routes, {
route: [active()]
});
router.route.active("Home") // true?route.response()clean-up
Previously, route.response() functions were passed a route object with the matched route's name, parsed params, and the location. These are now passed at the top-level. route is now the object of route interactions functions (pathname() and any you include).
{
response({ name, params, location, route }) {
const pathname = route.pathname(name, params);
}
}The set methods have also been removed. Instead, route.response() should return an object. The valid properties will be merged onto the response that is emitted. Valid properties are body, error, status, title, data, and redirectTo. Most of these are copied verbatim, but redirectTo uses the name and params it is given to form a location's pathname.
{
response() {
return {
body: About,
title: "About Us"
};
}
}
// redirecting
{
name: "Old Route"
response({ params }) {
return {
redirectTo: {
name: "New Route",
params
}
}
}- No more emitting misses
When no routes match a location, a response is not emitted. An application should always define its own catch-all route to handle these. The path string "(.*)" will match everything, so it is the easiest way to make a catch-all.
const routes = [
// ...,
{
name: "Not Found",
path: "(.*)",
// ...
}
];A console warning will be called when no routes match and describe the same fix, so any issues with this should be easy to catch.
- No more
details
Thedetailsprop passed to the various link components never felt right. These properties (hash,queryandstate) are now passed directly to the link components.
// before
<Link to="Yo" details={{ hash: "ahoy" }}>Howdy</Link>
// new
<Link to="Yo" hash="ahoy">Howdy</Link>
- Reworked the React
<Active>component and dropped<Link active>.
<Active> now takes a render-invoked children prop. That function will be given a boolean of whether or not it is "active". It will also receive the current response object as its second argument, which can be useful if you want to do additional active checks (e.g. compare query objects or hashes).
To style a <Link> as active, it should now be rendered in an <Active>'s children render-invoked prop.
<Active name="Home">
{active => (
<Link to="Home" className={active ? "active" : ""}>Home</Link>
)}
</Active>A wrapper component can be used to handle lots of links that want to be styled the same way.
const ActiveLink = ({ to, params, partial = true, ...rest }) => (
<Active name={to} params={params} partial={partial}>
{active => (
<Link
to={to}
params={params}
{...rest}
className={active ? "active" : ""}
/>
)}
</Active>