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

useSearchParams suggestion #328

Open
rattleSSnake opened this issue May 28, 2023 · 14 comments
Open

useSearchParams suggestion #328

rattleSSnake opened this issue May 28, 2023 · 14 comments
Labels
enhancement New feature or request

Comments

@rattleSSnake
Copy link

It would be very needed that setSearchParams from solid-start works like setting state, meaning it holds previous value and overwrites existing state when omitting prev. That way, it both works when you want to overwrite existing or append.

setSearchParams({ hello: "world" }) //overwrites existing
setSearchParams(prev => ({...prev, hello: "world" })) //appends
@mtt-artis
Copy link

Undefined for delete ?

setSearchParams(prev => ({...prev, hello: undefined })) // delete

@rattleSSnake
Copy link
Author

rattleSSnake commented May 28, 2023

If searchParams returned an Object instead of a Proxy, one could do:

setSearchParams(prev => {
  delete prev["hello"]
  return prev
})

It should return an object imo:

export function useSearchParams() {
  let initial = new URLSearchParams(isServer ? {} : window.location.search);

  const params = () => {
    const obj = {};
    for (const v of initial.keys()) obj[v] = initial.get(v);
    return obj;
  };

  const add = obj => {
    for (const key in obj) initial.append(key, obj[key]);
    const search = initial.length ? `?${initial.toString()}` : "";
    window.history.replaceState(null, "", window.location.pathname + search);
  };

  const setParams = arg => {
    if (typeof arg === "object") {
      initial = new URLSearchParams(); //reset
      add(arg);
    } else if (arg instanceof Function) {
      const old = params();
      initial = new URLSearchParams(); //reset
      add(arg(old));
    }
  };

  return [params, setParams];
}

@rattleSSnake rattleSSnake changed the title setSearchParams suggestion useSearchParams suggestion May 28, 2023
@mtt-artis
Copy link

i think proxy is needed for reactivity
the current useSearchParams function could be updated
didn t try tbh

https://github.com/solidjs/solid-router/blob/HEAD/src/routing.ts#L100-L115

export const useSearchParams = <T extends Params>(): [
  T,
  (newParams: SetParams | ((current: Readonly<T>) => SetParams), options?: Partial<NavigateOptions>) => void
] => {
  const location = useLocation();
  const navigate = useNavigate();
  const setSearchParams = (params: SetParams | ((params: Readonly<T>) => SetParams), options?: Partial<NavigateOptions>) => {
    const searchString = typeof params === "function"
      ? untrack(() => mergeSearchString("", params(location.query as T)))
      : untrack(() => mergeSearchString(location.search, params));
    navigate(location.pathname + searchString + location.hash, {
      scroll: false,
      resolve: false,
      ...options
    });
  };
  return [location.query as T, setSearchParams];
};

@rattleSSnake
Copy link
Author

rattleSSnake commented May 28, 2023

But since it is a proxy, how would you deal this situation ?

setSearchParams(prev => {
  delete prev["something"];
  console.log(prev)
  return prev
});

Also on this line it should be:

: untrack(() => mergeSearchString("", params));

to make overwrite work

@mtt-artis
Copy link

you might be able to use produce https://www.solidjs.com/docs/latest/api#produce
again, i didn t try


: untrack(() => mergeSearchString("", params));

would be a breaking change

@rattleSSnake
Copy link
Author

rattleSSnake commented May 28, 2023

You think it's ok to design it like that ? The user should be able to delete key in this way imo:

setSearchParams(prev => {
  delete prev["something"];
  console.log(prev)
  return prev
});

@mtt-artis
Copy link

I don't really like the delete keyword in general so this doesn't bother me but that's a personal preference and I'm not a core member ;)

I think Ryan spoke about this pattern for store in one of his streams. I'll add the link if I find it.

@rattleSSnake
Copy link
Author

rattleSSnake commented May 30, 2023

Thank you for your contribution @mtt-artis.
I believe you didn't include this feature that could be a breaking change.

: untrack(() => mergeSearchString("", params));

would be a breaking change

setSearchParams should behave like state, where a plain object would overwrite existing params.

setSearchParams({ lonelykey: "i-overwrite" });

Imo if we don't want to change this there is no point to add callback

@mtt-artis
Copy link

mtt-artis commented May 31, 2023

Hey @rattleSSnake
I share the logic here but I don't think the breaking change is a good idea.
Noneless I'd be happy to make the change and refactor mergeSearchString if the reviewer asks me to do so.

@rattleSSnake
Copy link
Author

rattleSSnake commented May 31, 2023

With the update, can we somehow reset search params (by deleting every previous key I guess) ?

What happens if I do this: setSearchParams(prev => ({ omitprev: "what" }));

@mtt-artis
Copy link

This will reset search params

setSearchParams(prev => ({ }));

@ryansolid ryansolid transferred this issue from solidjs/solid-start Dec 19, 2023
@ryansolid ryansolid added the enhancement New feature or request label Jan 30, 2024
@chiefcll
Copy link

chiefcll commented Sep 8, 2024

Just to add in to this - I'm looking to support Browsers before Proxy support is added. I'd prefer for it also to be a plain Object. If there is any way to do this without proxy (maybe defining which search or query params one was looking for). I'll be diving into Router code this week probably forking it to remove that for now as I don't need reactive params.

@ryansolid
Copy link
Member

Just to add in to this - I'm looking to support Browsers before Proxy support is added. I'd prefer for it also to be a plain Object. If there is any way to do this without proxy (maybe defining which search or query params one was looking for). I'll be diving into Router code this week probably forking it to remove that for now as I don't need reactive params.

It's tricky from a general sense because params can change shape, ie be added removed. My gut is I can't just get rid of the proxy here.

@chiefcll
Copy link

I'm looking at this now. I think for params you could process all the routes and look for all the defined params and create an object with get / set for each of the possible params from the routes.

For Query params you'd need to be told all the possible query params. I think it's doable to avoid the proxy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants