#ReferenceError: navigator is not defined
1 messages · Page 1 of 1 (latest)
Navigator does not exist on the server and certain browser providers (electron apps if I remember correct). If you’re only running in a browser and navigator should exist then you need to check that you’re currently in a hydrated state because remix on the server does not have a navigator item. You can do this by using sergiodxa’s remix utils to useHydrated or useClientOnly. Either of which should help you get it working
That's more complicated than i was expecting but thanks. I installed it.
I tried this code:
<ClientOnly>
<ShareButton />
</ClientOnly>
I am getting a very unhelpful error:
renderWithHooks@http://localhost:3000/build/entry.client-IWXTCWXB.js:11766:35
updateFunctionComponent@http://localhost:3000/build/entry.client-IWXTCWXB.js:14154:43
beginWork$1@http://localhost:3000/build/entry.client-IWXTCWXB.js:19251:31
performUnitOfWork@http://localhost:3000/build/entry.client-IWXTCWXB.js:18699:31
workLoopSync@http://localhost:3000/build/entry.client-IWXTCWXB.js:18635:30
renderRootSync@http://localhost:3000/build/entry.client-IWXTCWXB.js:18614:27
recoverFromConcurrentError@http://localhost:3000/build/entry.client-IWXTCWXB.js:18236:42
performConcurrentWorkOnRoot@http://localhost:3000/build/entry.client-IWXTCWXB.js:18184:56
performConcurrentWorkOnRoot@[native code]
workLoop@http://localhost:3000/build/entry.client-IWXTCWXB.js:200:50
flushWork@http://localhost:3000/build/entry.client-IWXTCWXB.js:179:30
performWorkUntilDeadline@http://localhost:3000/build/entry.client-IWXTCWXB.js:387:50
Is that the entirety of the error message? No other message just a stack trace? The only other thing I can say is the clientOnly generally wants a fallback component but I don’t think it’s required. So it shouldn’t be an issue if you don’t provide it
The docs say its recommended but not required
If I build it and run start (rather than dev) I get this error. It's no more helpful though really:
TypeError: l is not a function
at h (http://localhost:3000/build/routes/index-AODIA3WW.js:1:286)
at mu (http://localhost:3000/build/entry.client-ZOIG5E4U.js:6:19484)
at Pi (http://localhost:3000/build/entry.client-ZOIG5E4U.js:8:3153)
at Xa (http://localhost:3000/build/entry.client-ZOIG5E4U.js:8:44792)
at $a (http://localhost:3000/build/entry.client-ZOIG5E4U.js:8:39724)
at Zf (http://localhost:3000/build/entry.client-ZOIG5E4U.js:8:39655)
at br (http://localhost:3000/build/entry.client-ZOIG5E4U.js:8:39515)
at Ui (http://localhost:3000/build/entry.client-ZOIG5E4U.js:8:35905)
at Ha (http://localhost:3000/build/entry.client-ZOIG5E4U.js:8:34858)
at Cl (http://localhost:3000/build/entry.client-ZOIG5E4U.js:1:1741)
I find the error messages in Remix are usually pretty terrible 🤷♂️
I don’t fully disagree. But I think it’s more of a SSR react is pretty new and not very well documented yet so there’s a lot of bleeding edge of tech pain. The is not a function is somewhat interesting because that to me means you might have a react component that isn’t well defined and it’s trying to call it but it’s not returning jsx sometimes. Idk if you’re using typescript or not but I believe a react component function needs to always return html even if it’s an empty fragment
Are you able to provide more code of what’s happening in share button or around that area? @rancid sand
In the React docs there's an example of returning null (as something has to be returned) and that is a pattern I used here. Perhaps that is causing the issue. https://react.dev/learn/conditional-rendering#:~:text=If isPacked is true%2C the component will return nothing%2C null. Otherwise%2C it will return JSX to render.
My code:
function ShareButton() { if (navigator.canShare) { return ( <button onClick={handleShare} className="button"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="feather feather-share-2"><circle cx="18" cy="5" r="3"></circle><circle cx="6" cy="12" r="3"></circle><circle cx="18" cy="19" r="3"></circle><line x1="8.59" y1="13.51" x2="15.42" y2="17.49"></line><line x1="15.41" y1="6.51" x2="8.59" y2="10.49"></line></svg>Share</button> ) } else {return null} }
I’ve had many complaints in typescript saying “cannot be used as a JSX element because it doesn’t always return html” not exactly that, but that sort of idea. Try instead return <><>
<><>*
It keeps removing back slash but you get the idea lol
I've not been using Typescript, maybe I should. I now get the error TypeError: children is not a function
Ah, very interesting. And that’s happening in the clientOnly zone I’m guessing. There must be something strange going on with the share button component
I tried moving the logic
<ClientOnly>
{ navigator.canShare && <ShareButton />} </ClientOnly>
This is again giving me the navigator is not defined error 🤯 😿
Man, that navigator is really causing issues. Try one thing for me for sanity. UseHydrated instead and do something like:
Const hydrated = useHydrated()
{hydrated && navigator.canShare && <ShareButton/>
I typically useHydrated and do those kinda checks but usually with ternaries. clientOnly should be doing this under the hood but just in case some weird thing is happening with rendering
Sorry I can’t pretty format. On phone lol
Amazing. Thanks that worked! 🙂
So very strange clientOnly didn’t do the trick
It really shouldn't be this hard. Surely people need to use navigator all the time?
Eh, I’ve made a fairly large app and never touched the navigator lol
The window is more common
I might raise an issue in the utils project
On remix itself it recommends doing if(window){} so you can probably do the same with if(navigator){} I just know a lot of remix utils are pretty useful and usually are my preferred way of guaranteeing a window or other browser apis
useHydrated in particular has been super useful for me all through my app. Whereas always checking for windows and such feels less good to me
Oh I hadn't even thought of doing a conditional for navigator, that makes sense
I didn’t recommend the navigator check because I wasn’t sure if doing that one in particular. I haven’t seen any examples but in theory it should work just the same. Slightly sick so my brain isn’t fully there