gatsby-packages
gatsby-packages copied to clipboard
`gatsby-plugin-use-query-params` not working with Gatsby V4
After following the migration guide and updating from Gatsby V3 to V4, I'm having problems with useQueryParams()
in my project. I suspect it has something to do with how all of my other gatsby-plugin-*
packages needed to be updated for V4, but an update wasn't available for gatsby-plugin-use-query-params
.
Do you think this is the cause of the problem?
If you would like, I'll try to make a new repository to reproduce the issue.
Same here. Using any setter with "replaceIn" causes my Gatsby site to render a 404.
Looks like at the heart of the plugin it's wrapping the root element with a QueryParamProvider
from the use-query-params
package. Without it, use-query-params complains that it needs to consume that context.
import React from "react";
import { Location, globalHistory } from "@reach/router";
import { QueryParamProvider } from "use-query-params";
export default ({ children }) => (
<Location>
{({ location }) => (
<QueryParamProvider location={location} reachHistory={globalHistory}>
{children}
</QueryParamProvider>
)}
</Location>
);
Somehow this isn't sufficient anymore.
Workaround 💪
UPDATE: You can try the Replacement Hook Solution below which makes this plugin obsolete.
I realized this had something to do with Reach router detecting the URL changes and that there are a few ways we can tell Gatsby to ignore certain paths.
Limitations
The limitation to this workaround is that you'll need to configure the paths to the pages that set query params. It's not a fix for every page. Pages that only get query params (no set calls) are unaffected by the bug.
However this workaround can get you up and running until there's an official fix if your use case is that you only need to set query params on a handful of pages.
Workaround # 1
Use gatsby-plugin-create-client-paths
to tell Gatsby's root router to ignore the query params when they change. This is equivalent to setting your page up to have a client router, except we won't actually nest a router.
-
npm install gatsby-plugin-create-client-paths
- In gatsby-config, add the following plugin:
{ // Add paths to pages that set query params here. // This is a workaround: https://github.com/alexluong/gatsby-packages/issues/41 resolve: `gatsby-plugin-create-client-paths`, options: { prefixes: [`/path-to-page-needing-query-params/*`] }, },
- Replace
path-to-page-needing-query-params
with the path to the page that needs to set query params. You can add as many path prefixes to that array as you'd like. You'll need one for each page that sets query params.
Using this approach, you can specify any page paths right from gatsby-config. This makes it pretty easy to maintain.
Workaround # 2
Use splat routes for the pages that need query params.
- Move all of your gatsby pages needing query params into a folder with the same name as the file, and rename them to
[...].js
. For example,/src/pages/blog.js
becomes/src/pages/blog/[...].js
Using this approach, you will need to change the files in /src/pages
. This is a bit more of a hassle than workaround # 1, and harder to maintain. Not sure if this will work for programmatically created pages, either.
Thanks for the workarounds, @justinmahar! I'll see if one of them fixes the issue for me when I have time. It would be really nice if this issue gets fixed before then.
Has anyone solved this problem yet? If not I would be willing to make a PR
@byronlanehill I haven't. This issue was just the straw that broke the camel's back and made me switch the site I was having problems with over to Next JS. I'm only aware of the workaround that @justinmahar posted previously on this issue.
@byronlanehill If you would be willing to make a PR, that would be fantastic. Unfortunately, because of the particularities of the app I'm working on, we can't use the workaround without hard-coding a bunch of paths, and that's simply unmaintainable. Without this package being updated, we'd have to switch to a different package.
@Ksan8 I actually recently switched to using use-query-params directly in my layout that wraps each page as it is only a few lines of code and reduces complexity in my opinion. If you'd like me to share the code is be more than happy to
@byronlanehill That would be fantastic. Thank you!
wrapPageElement.jsx
import React from 'react';
import { navigate } from 'gatsby';
import { QueryParamProvider } from 'use-query-params';
function generatePath(location) {
return location.pathname + location.search;
}
const history = {
push: (location) => {
navigate(generatePath(location), { replace: false, state: location.state });
},
replace: (location) => {
navigate(generatePath(location), { replace: true, state: location.state });
},
};
export const wrapPageElement = ({ element, props }) => (
<QueryParamProvider history={history} location={props.location}>
{element}
</QueryParamProvider>
);
gatsby-browser.js
export { wrapPageElement } from './wrapPageElement';
gatsby-ssr.js
export { wrapPageElement } from './wrapPageElement';
Test before putting into production of course, but this has worked for me adequately. I don't think it would keep location.state if you needed that, and it wouldn't keep hashes by default either.
shouldUpdateScroll.js
// If the pathname hasn't changed on an update, such as changing a query parameter
// then the page should not scroll to top.
export function shouldUpdateScroll({ prevRouterProps, routerProps }) {
return prevRouterProps?.location?.pathname !== routerProps.location.pathname;
}
gatsby-browser.js
export { shouldUpdateScroll } from './shouldUpdateScroll';
I also keep this in the same project. It preserves the scroll if only query parameters changed, which is required in most cases when you are using use-query-params.
I will see about publishing a PR this weekend so we can get the functionality into this plugin, but if it is urgent you can add this directly to your project for now.
@Ksan8 I updated the code for the wrapPageElement API and that should fix the previous problems I mentioned.
@byronlanehill Worked like a charm! I do notice that sometimes there is a quick page-reload flicker, but it doesn't seem to be happening consistently. Thanks again.
@Ksan8 Is it happening in production or just in dev?
@byronlanehill The flicker seems to happen (intermittently) with both a dev and prod build, though I haven't yet deployed to Staging to check fully. It's not a major concern, just something I noticed.
Okay, let me know how that goes! I will likely use this exact code to make a PR for this package, so hopefully we can get that bug worked out before then
Any chances this will get fixed?
Bumping this again, running into this issue myself.
"gatsby-plugin-use-query-params": "^1.0.1",
"use-query-params": "^1.2.3",
"gatsby": "^4.3.0",
I managed to get around the 404 issue by removing both use-query-params
+ gatsby-plugin-use-query-params
and used other library instead (query-string
for grabbing params works well for me with useState).
Then I use window.history.replaceState({...})
to update my query/page.
I can confirm that workaround #1 works.
Replacement Hook Solution
I've created a hook solution that incorporates the suggestions from @dumle11 above to eliminate the need for this plugin altogether.
This hook solution is now available via the npm library react-use-query-param-string.
You can view the code for the hook code here.
So i have two components that I'm using useQueryParamString one to set the query param and one to get it. So when i change the query with my setter component it doesn't re-render and the second component never gets the new query param value
Ahh yeah, that's a use case the hook def doesn't cover. I might end up making a context wrapper for this to address that.
@justinmahar Thank you for spending your time on this
@ixhukellari Alright! So I tackled this for a bit and decided to go with a lighter weight event emitter approach. When changing params, all hooks fetch the latest value.
All you have to do is update the library and things should magically work ;)
npm install react-use-query-param-string@latest
Let me know if that fixes the issue.
@justinmahar Sorry i just saw this. I just tested it and it works. Thank you so much!
@justinmahar Sorry i just saw this. I just tested it and it works. Thank you so much!
Welcome!
@justinmahar your cool new hook worked for me too! Thanks for putting that together 💪
@justinmahar -- came back here to thank you for your contribution. it has solved the issue after a bit of head scratching.