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

separate instances of useSearchParams do not update the searchParams in concert #113

Open
ChristopherChudzicki opened this issue Jun 20, 2024 · 0 comments
Labels
bug Something isn't working

Comments

@ChristopherChudzicki
Copy link
Contributor

https://github.com/mitodl/course-search-utils/compare/cc/useSearchParams-bug?expand=1

Expected Behavior

setSearchParams(current => next) should always update the search params and should use the current value.

Current Behavior

Separate instances of setSearchParams overwrite each other for updates within the same render.

Steps to Reproduce

See the (failing) test added in https://github.com/mitodl/course-search-utils/compare/cc/useSearchParams-bug?expand=1#diff-57f641eeee56cf15d2f3647e24ee973979cc56e0dc15566cbda0db31ed9da952R143

Additional Details

Fixing this may not be a high priority. We have a workaround. But I wanted to leave notes for our future selves.

React Query's [searchParams, setSearchParams] = useSearchParams() hook is advertised as being similar to React's builtin [state, setState] = useState() hook, but using the router's search parameters as the state.

However, a major caveat is that multiple updates within the same render cycle do not use current value of search parameters:

setSearchParams("?a=1")
setSearchParams(current => {
  const copy = new URLSearchParams(current)
  copy.set("b", 2)
  return copy
})
// Expected: `?a=1&b=2`
// Actual: `?b=2

See

course-search-utils makes heavy use of setting search params, and it's useful to be able to set the parameters independently in different locations. As such, course-search-utils exports a wrapped version of useSearchParams that addresses this issue.

However, separate instances of our custom useSearchParams still exhibit this behavior:

import { useSearchParams } from "@mitodl/course-search-utils/react-router"

const [_, setSearchParams1] = useSearchParams()
const [_, setSearchParams2] = useSearchParams()

// then later
setSearchParams1(current => {/* append parameter a= 1 */})
setSearchParams2(current => {/* append parameter a= 2 */})
// results in only the latest update

To be clear, both updates occur correctly if there's only one occurrence of useSearchParams.

See https://github.com/mitodl/course-search-utils/compare/cc/useSearchParams-bug?expand=1#diff-57f641eeee56cf15d2f3647e24ee973979cc56e0dc15566cbda0db31ed9da952R143 for a test demonstrating this issue

Concrete example and Workaround

A concrete example of this occurring was in mitodl/mit-learn#1132, where two separate callbacks were fired on the same click, one updating page=1 and the other updating resource_type.

Workaround: Pass the same setSearchParam setter from parent rather than accessing via hook.

Possible Solution

Our wrapped useSearchParam stores the current search params in a ref. That ref could be put in a context, so separate "instances" of the hook share it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant