I assume that exports.wrapRootElement in "gatsby-browser.js" is meant to be a component that accepts another component and well... wraps it.
As such, I assume I could use hooks inside this component. Take a look at this simplified example of my "gatsby-browser.js":
// Assigning the function directly to wrapRootElement causes a react hooks
// linter error because it thinks wrapRootElement is not a function component.
// Probably because the name starts with a lowercase letter?
const Wrapper = ({ element }) => {
const [loggedIn, setLoggedIn] = useState(/* some code */)
useEffect(() => {
firebase.auth().onAuthStateChanged(user => {
setLoggedIn(!!user)
})
})
return (
<FirebaseContext.Provider value={{ loggedIn }}>
{element}
</FirebaseContext.Provider>
)
}
exports.wrapRootElement = Wrapper
This throws the following error:
Unhandled Rejection (Error): Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
Off the top of my head try this:
const FireBaseApp = () => {
const [loggedIn, setLoggedIn] = useState(/* some code */)
useEffect(() => {
firebase.auth().onAuthStateChanged(user => {
setLoggedIn(!!user)
})
})
return (
<FirebaseContext.Provider value={{ loggedIn }}>
{element}
</FirebaseContext.Provider>
)
}
const Wrapper = ({ element }) => {
return <FireBaseApp element={element} />
}
exports.wrapRootElement = Wrapper
So we're just wrapping everything in a fragment so that it is now a component. I think that should work
Thanks, this worked! I'm a bit surprised, because I thought a functional component in React was just a function that returns JSX, but I guess it also depends on the way it is called behind the scenes?
Also for future reference, so I can debug these things on my own. What's the easiest way to find where wrapRootElement is in the source code? Do I just need to grep the codebase?
@vedantroy wrapRootElement is here.
If you look at the way the apiRunner is called, you'll see why it doesn't work using hooks inside of wrapRootElement. It has to be a react element that contains the hook, and that's what you're doing by wrapping it with another React Functional Component.
I actually just got done talking about this here, the other day.
Most helpful comment
Off the top of my head try this:
So we're just wrapping everything in a fragment so that it is now a component. I think that should work