Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add to helper #188

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1550,6 +1550,44 @@ export default function Component() {

Now you can see in your DevTools that when the user hovers an anchor it will prefetch it, and when the user clicks it will do a client-side navigation.

### Generate URL strings for Link/Form

If you use `<Link>` with search params, specially dynamic values like a pagination, you will have to create the URL with the search params manually.

You may have something like this:

```tsx
return <Link to={`?page=${page + 1}&search=${search}`}>Next</Link>;
```

Or maybe using URLSearchParams:

```tsx
let searchParams = new URLSearchParams();
searchParams.set("page", page + 1);
searchParams.set("search", search);
return <Link to={`?${searchParams.toString()}`}>Next</Link>;
```

Or even using the `useSearchParams` hook to edit the current ones:

```tsx
let [searchParams] = useSearchParams();
searchParams.set("page", page + 1);

return <Link to={`?${searchParams.toString()}`}>Next</Link>;
```

All of these are valid solutions, but they can be a bit verbose and repetitive, and you may forget to add the `?` before the search params, the `to` function in Remix Utils lets you do this in a more concise way.

```tsx
import { to } from "remix-utils";

return <Link to={to({ page: page + 1, search })}>Next</Link>;
```

The `to` is going to generate a URL like `?page=2&search=hello` so you can pass it to `<Link to/>`, `<Form action>`, `useFetcher().load()`, `useFetcher().submit()`, or `useSubmit()()`.

## Author

- [Sergio Xalambrí](https://sergiodxa.com)
Expand Down
1 change: 1 addition & 0 deletions src/common.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./common/promise";
export * from "./common/to";
23 changes: 23 additions & 0 deletions src/common/to.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { LinkProps } from "@remix-run/react";

type To = Partial<Pick<URL, "hostname" | "pathname" | "hash" | "search">> & {
searchParams?: ConstructorParameters<typeof URLSearchParams>["0"];
};

export function to(partial: To): LinkProps["to"] {
let url = new URL("http://localhost");

if (partial.hostname) url.hostname = partial.hostname;
if (partial.pathname) url.pathname = partial.pathname;
if (partial.search) url.search = partial.search;
if (partial.searchParams) {
url.search = new URLSearchParams(partial.searchParams).toString();
}
if (partial.hash) url.hash = partial.hash;

let string = url.toString();

if (partial.hostname) return string;
if (partial.pathname) return string.slice("http://localhost".length);
return string.slice("http://localhost/".length);
}
30 changes: 30 additions & 0 deletions test/common/to.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { to } from "../../src";

describe(to.name, () => {
test("returns a string with the changed pathname", () => {
expect(to({ pathname: "/foo/bar" })).toBe("/foo/bar");
});

test("returns a string with the changed search", () => {
expect(to({ search: "?foo=bar" })).toBe("?foo=bar");
});

test("returns a string with the changed hash", () => {
expect(to({ hash: "#foo" })).toBe("#foo");
});

test("returns a string with the changed search params", () => {
expect(to({ searchParams: { foo: "bar" } })).toBe("?foo=bar");
});

test("returns a string with the changed search params (array)", () => {
expect(
to({
searchParams: [
["foo", "bar"],
["foo", "baz"],
],
})
).toBe("?foo=bar&foo=baz");
});
});