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

问题描述 投票:0回答:1

我正在开发一个 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 内,如上所示。

什么可能导致此问题以及如何解决?

javascript reactjs react-hooks react-router react-router-dom
1个回答
0
投票

在您的

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
© www.soinside.com 2019 - 2024. All rights reserved.