代码之家  ›  专栏  ›  技术社区  ›  Aaron Tauro

useLocation钩子错误:“useLocation()只能在React应用程序中的<Router>组件的上下文中使用”

  •  0
  • Aaron Tauro  · 技术社区  · 11 月前

    我正在开发一个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钩子正在应用程序组件中使用,该组件封装在RouterProvider中,如上所示。

    是什么导致了这个问题,我该如何解决?

    2 回复  |  直到 11 月前
        1
  •  1
  •   Mykola Tunyk    11 月前

    在你的 App 组成部分 useLocation 正在被直接调用 应用程序 作用然而 RouterProvider 应该包裹整个组件树,其中 使用位置 使用钩子。要修复错误,请移动 使用位置 将逻辑打包到一个单独的组件中,然后将组件树包装在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
    
        2
  •  1
  •   abuzain    11 月前

    原因

    您会收到此错误,因为useLocation只能在组件的上下文中使用)。在您的情况下,该应用程序并不直接在上下文中。

    如何修复它?

    您必须确保在路由器上下文中的组件内使用useLocation钩子。为此,您需要以在路由器呈现的组件中调用useLocation的方式重构代码。 创建一个用于处理位置相关逻辑的分离组件。并将该组件添加为带索引的默认路由,并在那里执行与位置相关的任务。