0

I have a tag input that produces an array of tags. Using NextJs's useRouter, I want to add those tags as query string params as they are added. I also need to preserve the current query string params, since other filters, searches, and pagination need to remain.

Here is how I'm currently doing it.

const router = useRouter();
const { query } = router;
const [tags, setTags] = useState([]);

useEffect(() => {
  router.push({
    query: {
      ...query,
      tags,
    },
  });
}, [tags, router, query]);

return (
  <>
    <TagInput tags={tags} setTags={setTags} placeholder="Search by tags" />
  </>
);

However, this causes an infinite render since the useEffect updates the query but also has query as a dependency. If I remove query as a dependency, it works fine, but I get the missing dependency linting error.

Edit: Here is a codesandbox with a minimal example that reproduces the issue. It works as is, but if you uncomment the query dependency, infinite loop. https://codesandbox.io/s/next-js-dynamic-routing-forked-rlxuqh?file=/pages/index.js

DasBeasto
  • 2,082
  • 5
  • 25
  • 65
  • Are tags the only thing that you're storing in the query object? The example (inside router.push) makes it look like there might be other values stored in the query object. – Stafford Rose May 20 '22 at 02:25
  • @StaffordRose there are others, as I said in the question I also need to preserve the current query string params, since other filters, searches, and pagination need to remain. – DasBeasto May 20 '22 at 12:35
  • @lpizzinidev The TagInput component is a little big and I think would distract from the main question since the tag input doesn't seem to have an effect, I just added a codesandbox link that lets you add tags with just a button to demonstrate that. It works as is but as soon as you uncomment the query dependency the infinite loop starts before you can even add any tags. – DasBeasto May 20 '22 at 12:45

1 Answers1

2

One way this can be done is to directly update the query object and read the tags from the url, rather than storing the tags in state.

const router = useRouter();
const { query } = router;

const setTags = useCallback((tags) => {
  router.push({
    query: {
      ...query,
      tags
    }
  });
}, [router, query]);

return (
  <>
    <TagInput tags={query.tags || []} setTags={setTags} placeholder="Search by tags" />
  </>
);
Stafford Rose
  • 769
  • 4
  • 9