I'm developing a React application and I'm encountering an error when using the useLocation
hook from the react-router-dom
library. The error message I receive is:
Error: useLocation() may be used only in the context of a component.
Here is the relevant part of my App.js
file:
import { useEffect, useState } from 'react'
import { createBrowserRouter, RouterProvider, useLocation } from 'react-router-dom'
// Components
import Navigation from './components/Navigation'
import Section from './components/Section'
import Product from './components/Product'
import Login from './components/Login'
// ABIs
import Dappazon from './abis/Dappazon.json'
// Config
import config from './config.json'
const ethers = require('ethers')
function App() {
const [provider, setProvider] = useState(null)
const [dappazon, setDappazon] = useState(null)
const [account, setAccount] = useState(null)
const [electronics, setElectronics] = useState(null)
const [clothing, setClothing] = useState(null)
const [toys, setToys] = useState(null)
const [item, setItem] = useState(null)
const [toggle, setToggle] = useState(false)
const location = useLocation()
const togglePop = (item) => {
setItem(item)
toggle ? setToggle(false) : setToggle(true)
}
const loadBlockchainData = async () => {
const provider = new ethers.BrowserProvider(window.ethereum)
setProvider(provider)
const network = await provider.getNetwork()
const dappazon = new ethers.Contract(config[network.chainId].dappazon.address, Dappazon, provider)
setDappazon(dappazon)
const items = []
for (var i = 0; i < 9; i++) {
const item = await dappazon.items(i + 1)
items.push(item)
}
const electronics = items.filter((item) => item.category === 'electronics')
const clothing = items.filter((item) => item.category === 'clothing')
const toys = items.filter((item) => item.category === 'toys')
setElectronics(electronics)
setClothing(clothing)
setToys(toys)
}
useEffect(() => {
loadBlockchainData()
}, [])
const router = createBrowserRouter([
{
path: "/login",
element: <><Navigation account={account} setAccount={setAccount} /><Login /></>
},
{
path: "/",
element: <><Navigation account={account} setAccount={setAccount} /></>
},
{
path: "/Clothing&Jewelry",
element: <><Navigation account={account} setAccount={setAccount} /><Section title={"Clothing & Jewelry"} items={clothing} togglePop={togglePop} /></>
},
{
path: "/Electronics&Gadgets",
element: <><Navigation account={account} setAccount={setAccount} /><Section title={"Electronics & Gadgets"} items={electronics} togglePop={togglePop} /></>
},
{
path: "/Toys&Gaming",
element: <><Navigation account={account} setAccount={setAccount} /><Section title={"Toys & Gaming"} items={toys} togglePop={togglePop} /></>
},
])
return (
<>
<div>
{/* <Navigation account={account} setAccount={setAccount} /> */}
<RouterProvider router={router} />
{electronics && clothing && toys && location.pathname === '/' && (
<>
<h2>Dappazon Best Sellers</h2>
<Section title={"Clothing & Jewelry"} items={clothing} togglePop={togglePop} />
<Section title={"Electronics & Gadgets"} items={electronics} togglePop={togglePop} />
<Section title={"Toys & Gaming"} items={toys} togglePop={togglePop} />
</>
)}
{toggle && (
<Product item={item} provider={provider} account={account} dappazon={dappazon} togglePop={togglePop} />
)}
</div>
</>
);
}
export default App;
I have already ensured that RouterProvider
wraps the component that uses useLocation
, but the error persists. The useLocation
hook is being used within the App
component which is wrapped inside the RouterProvider
as shown above.
What could be causing this issue and how can I resolve it?
In your App
component, useLocation
is being called directly within the App
function. However, RouterProvider
is supposed to wrap the entire component tree where the useLocation
hook is used. To fix the error, move the useLocation
logic into a separate component, then wrap the component tree inside RouterProvider:
import { useEffect, useState } from 'react'
import { createBrowserRouter, RouterProvider, useLocation } from 'react-router-dom'
import Navigation from './components/Navigation'
import Section from './components/Section'
import Product from './components/Product'
import Login from './components/Login'
import Dappazon from './abis/Dappazon.json'
import config from './config.json'
const ethers = require('ethers')
const MainContent = ({ togglePop, provider, dappazon, account, electronics, clothing, toys, item, toggle }) => {
const location = useLocation()
return (
<>
{electronics && clothing && toys && location.pathname === '/' && (
<>
<h2>Dappazon Best Sellers</h2>
<Section title={"Clothing & Jewelry"} items={clothing} togglePop={togglePop} />
<Section title={"Electronics & Gadgets"} items={electronics} togglePop={togglePop} />
<Section title={"Toys & Gaming"} items={toys} togglePop={togglePop} />
</>
)}
{toggle && (
<Product item={item} provider={provider} account={account} dappazon={dappazon} togglePop={togglePop} />
)}
</>
)
}
function App() {
const [provider, setProvider] = useState(null)
const [dappazon, setDappazon] = useState(null)
const [account, setAccount] = useState(null)
const [electronics, setElectronics] = useState(null)
const [clothing, setClothing] = useState(null)
const [toys, setToys] = useState(null)
const [item, setItem] = useState(null)
const [toggle, setToggle] = useState(false)
const togglePop = (item) => {
setItem(item)
setToggle(!toggle)
}
const loadBlockchainData = async () => {
const provider = new ethers.BrowserProvider(window.ethereum)
setProvider(provider)
const network = await provider.getNetwork()
const dappazon = new ethers.Contract(config[network.chainId].dappazon.address, Dappazon, provider)
setDappazon(dappazon)
const items = []
for (var i = 0; i < 9; i++) {
const item = await dappazon.items(i + 1)
items.push(item)
}
setElectronics(items.filter(item => item.category === 'electronics'))
setClothing(items.filter(item => item.category === 'clothing'))
setToys(items.filter(item => item.category === 'toys'))
}
useEffect(() => {
loadBlockchainData()
}, [])
const router = createBrowserRouter([
{ path: "/login", element: <><Navigation account={account} setAccount={setAccount} /><Login /></> },
{ path: "/", element: <><Navigation account={account} setAccount={setAccount} /></> },
{ path: "/Clothing&Jewelry", element: <><Navigation account={account} setAccount={setAccount} /><Section title={"Clothing & Jewelry"} items={clothing} togglePop={togglePop} /></> },
{ path: "/Electronics&Gadgets", element: <><Navigation account={account} setAccount={setAccount} /><Section title={"Electronics & Gadgets"} items={electronics} togglePop={togglePop} /></> },
{ path: "/Toys&Gaming", element: <><Navigation account={account} setAccount={setAccount} /><Section title={"Toys & Gaming"} items={toys} togglePop={togglePop} /></> },
])
return (
<RouterProvider router={router}>
<MainContent
togglePop={togglePop}
provider={provider}
dappazon={dappazon}
account={account}
electronics={electronics}
clothing={clothing}
toys={toys}
item={item}
toggle={toggle}
/>
</RouterProvider>
)
}
export default App