Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

How to avoid 'Loader must not be called again with different options' error when using nonce in useJsApiLoader? #3023

Answered by kimitaka
chrisdueck asked this question in Q&A
Discussion options

Hello! I'm currently trying to make use of the nonce option in the useJsApiLoader hook.

After setting everything up it seemed to work as expected, but after I refresh the page and get a new nonce value, I end up with the error: Loader must not be called again with different options (I have double checked and the only difference in the options provided after refreshing is the nonce.)

I've read that the loader acts as a singleton and essentially no new instances are created are created as long as you pass the same settings, which makes sense to me, but in this case the nonce value has to be different (since it is a nonce).

I've seen from this issue that you could potentially reset the loader manually, which might help with getting around this, but since that would require using js-api-loader directly, I wouldn't be able to use the useJsApiLoader hook anymore.

It feels like I'm missing something, is there a better/recommended way to handle this scenario?

Many thanks in advance!

Editing to include my example in the comments:

https://stackblitz.com/edit/cd-rgmapi

Steps:

  1. Click 'Go to map' (map loads fine)
  2. Click 'Go home'
  3. Click 'Go to map' again (error appears)
You must be logged in to vote

Choose your preferred solution below.

  • Reuse the same nonce value
  • Ensure calling useJsApiLoader only once in your app
  • Load scripts manually without useJsApiLoader (I don't recommend this)

In most cases, it's enough to load scripts only once to use Google Maps API. Twice or more would mean something technically wrong in your app.

Calling useJsApiLoader with the same nonce value, loading scripts will be just skipped, and the same API instance will be reused, so you don't worry about security holes related to loading scripts with known nonce value. And ensure calling useJsApiLoader only once in your app is a good choice too.

Sample: https://stackblitz.com/edit/cd-rgmapi-pnhl9b?file=App.tsx

I...

Replies: 12 comments 23 replies

Comment options

@chrisdueck please provide minimal reproduction. If page re-renders, there should be completely new google maps instances, and useLoadScript should be called every time page refreshes, as completely new process. Not sure that it is related to page-refresh in your case.
Passible you need to wrap your options object into useMemo hook?
I could guess it is related with Strict mode or react@17 double executing component and calling the hook 2 times.

You must be logged in to vote
9 replies
Comment options

@chrisdueck hi you try set Id=yourId for all maps in all page you used, id the same

Comment options

@Ho-Ngoc-Thanh I am only using one map in one page and adding an Id makes no difference. You can easily check this with my example above.

Comment options

@JustFly1984 Do you have any further suggestions?

Comment options

@chrisdueck I found a solution for your example giving in your link, the issue is with nonce as it don't work when you change the value of nonce
I tried two ways and is working in both
solution 1. So in MapPage.tsx set nonce static
setNonce(nonce-691d29db-ab00-4bf6-94fa-168373d2fb7e);

solution 2. comment out nonce in Map.tsx
const { isLoaded, loadError } = useJsApiLoader({
googleMapsApiKey: '',
// nonce: nonce,
});

Hope it helps

Comment options

@ahmedmajidgit "Just don't use the nonce" is not a solution. The whole point of this discussion is that I need to use it. It is necessary for the content security policy of my site and it won't work without it.

I'm not sure you understand its purpose - nonce means number used once, so it has to change value each time it is used, otherwise it is pointless. The example doesn't need it because it's just for demonstration - I even commented the code saying that the generation of the nonce is being faked for the sake of the example.

Both of your suggestions completely avoid the problem.

Comment options

The problem is happening with me too, while trying on my own style, then copy pasting from the documentation and still would display the same error!
Hope someone could solve it.

You must be logged in to vote
1 reply
Comment options

Comment out or remove React.StrictMode in index.js file.

Comment options

Comment out or remove React.StrictMode in index.js file.

{/* <React.StrictMode> */}

{/* </React.StrictMode> */}

You must be logged in to vote
0 replies
Comment options

In my case, the problem was happened every time I add or edit something in useJsApiLoader :

const { isLoaded } = useJsApiLoader({
 id: "google-map-script",
 googleMapsApiKey: "Google Map API Key",
 libraries: ["places"],
 });

Reload the server, solve the issue for me

so every time you change useJsApiLoader you need to reload the dev server
Ctrl C and yarn dev

You must be logged in to vote
4 replies
Comment options

It sounds like you had a different problem to mine. The issue I'm facing can be replicated with my example above.

Comment options

resetting the dev server fixed it for me. Thank you @TheYass1n

Comment options

you have to extract libraries array into const outside of component scope.

Comment options

Thank you, it worked for me!

Comment options

You must be logged in to vote
2 replies
Comment options

This is not the problem I am asking about. You're not even using a nonce here, and I only have one component as you can see in my example.
(...and did you really just thumbs up and heart your own answer?)

Comment options

GoodLuck 👍

(...and yes I did, since they should not actually allow me to do that)

Comment options

Choose your preferred solution below.

  • Reuse the same nonce value
  • Ensure calling useJsApiLoader only once in your app
  • Load scripts manually without useJsApiLoader (I don't recommend this)

In most cases, it's enough to load scripts only once to use Google Maps API. Twice or more would mean something technically wrong in your app.

Calling useJsApiLoader with the same nonce value, loading scripts will be just skipped, and the same API instance will be reused, so you don't worry about security holes related to loading scripts with known nonce value. And ensure calling useJsApiLoader only once in your app is a good choice too.

Sample: https://stackblitz.com/edit/cd-rgmapi-pnhl9b?file=App.tsx

If you genuinely need to load API scripts multiple times with different nonce values each time because of your business requirements. In that case, you should load them without useJsApiLoader to not use @googlemaps/js-api-loader, dependee on @react-google-maps/api. Because @googlemaps/js-api-loader raise the error explicitly to avoid unexpected load duplication. This restriction applies even if it is the nonce parameter.

https://github.com/googlemaps/js-api-loader/blob/main/src/index.ts#L317
https://github.com/googlemaps/js-api-loader/blob/main/src/index.ts#L342

You must be logged in to vote
1 reply
Comment options

Thank you so much @kimitaka. This answer really helped me to understand the issue with my implementation.

Calling useJsApiLoader with the same nonce value, loading scripts will be just skipped

Reading this and realising from your example that I can simply move the nonce loading to the outer <App /> component, so it is only fetched on the very first load is what fixed the issue for me. It almost seems obvious now I look at it again!

Answer selected by chrisdueck
Comment options

in my nextjs project I use i18 framework.
i want to pass current locale (current active language) to language prop of useJsApiLoader, but if user changes the language exactly this error appears.
how would you recommend to use different language option without calling the loader again?

You must be logged in to vote
3 replies
Comment options

I think it's off-topic from chrisdueck's original question. I'll be able to help you if you post as your original.

Comment options

Comment options

The issue with language is the reason this library exists in first place. I've made a LoadScript component which behaved correctly on language change, but it was 4 years ago. You can look at gatsby-example package for implementation details, but in short - you can do that.

Comment options

nonce itself is "number once" so it should not be changed at runtime in the browser.

Nonce is set by the web server on both, header and html, and guaranties that the code running is the code provided by the server.

There should not be change of nonce for the document without page reload.

If you are doing SSR, nonce should change on navigation, cos it calls server with full page reload.
If you are doing SPA, nonce can't change on navigation, cos navigation is using only browser API, without calling the web server.

To get new nonce, both in headers and in html you have to call a web sever and get a fresh page.

You must be logged in to vote
0 replies
Comment options

can I just assign a string value that won't change at all, or it's not recommended ?

 const { isLoaded, loadError } = useJsApiLoader({
 googleMapsApiKey: `${googlePlacesKey}`,
 nonce: "map",
 libraries: ["places"],
 });
You must be logged in to vote
0 replies
Comment options

I faced the same problem when trying to set up I18n with the useJsApiLoader hook.
Found the solution here: #3168

You must be logged in to vote
0 replies
Comment options

I found the same problem, this one because I store my API keys in my backend, any workaround to this one? because useJsApiLoader cannot be used inside a conditional

You must be logged in to vote
3 replies
Comment options

@Novizh You can have whole component which uses useJsApiLoader rendered under conditional. Just lift your conditional up the component tree into parent's JSX

Comment options

I assume I need to pass the API key as a prop to the child component?

Comment options

@JustFly1984 it works, thanks mate!

Comment options

Just in case this helps anyone, after trying various things, what worked for me was clearing the cookies and site data. Seems like some config data was getting persisted that was causing the "Loader must not be called again with different options" error.

You must be logged in to vote
0 replies
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

AltStyle によって変換されたページ (->オリジナル) /