我正在开发一个 React 应用程序,在使用
useLocation
库中的 react-router-dom
挂钩时遇到错误。我收到的错误消息是:
错误:useLocation()只能在组件上下文中使用。
这是我的
App.js
文件的相关部分:
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;
我已经确保 RouterProvider 包装了使用 useLocation 的组件,但错误仍然存在。 useLocation 钩子在 App 组件中使用,该组件被包装在 RouterProvider 内,如上所示。
什么可能导致此问题以及如何解决?
在您的
App
组件中,useLocation
直接在 App
函数中调用。然而, RouterProvider
应该包裹使用 useLocation
钩子的整个组件树。要修复该错误,请将 useLocation
逻辑移至单独的组件中,然后将组件树包装在 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