2

所以我有一个导航栏组件,如果我从“/sites/1”到“/categories/1”或任何带有“/sites”到“/categories”甚至“/sites/1”的东西,我创建的链接工作正常到“/sites”,但当我在一个类别显示页面上时不起作用,即“/categories/1”或“/categories/3”并尝试使用路径“/categories/5”转到另一个类别显示页面例如。我认为问题与确切路径是动态的事实有关,并且路由器将两条路径视为同一件事,直到硬重新加载。下面是我的代码。有什么方法可以使用 Link 并让该组件重新渲染,还是每次都必须使用锚标记并重新加载?

import React, { useState, useEffect } from "react"
import { Switch, Route, Link, Redirect } from "react-router-dom"

import SitesIndex from "./SitesIndex";
import SiteShow from "./SiteShow";
import AddNewSiteForm from "./AddNewSiteForm"
import CategoryShow from "./CategoryShow"

const NavBar = props => {
  const [categories, setCategories] = useState([])

  const fetchCategories = async() =>{
    try {
      const response = await fetch("/api/v1/categories")
      if(!response.ok){
        const errorMessage = `${response.status} (${response.statusText})`
        const error = new Error(errorMessage)
        throw(error);
      }
      const categoryData = await response.json();
      setCategories(categoryData.categories)
    } catch (error) {
      console.error(`Error in fetch: ${error.message}`)
    }
  }

  useEffect(() =>{
    fetchCategories()
  },[])

  const categoryLinks = categories.map(category =>{
    return(
      <li key={category.id} >
        <Link to={`/categories/${category.id}`}>{category.name}</Link>
      </li>
    )
  })

  categoryLinks.unshift(
    <li key={0}>
      <Link to={`/sites`} >Home</Link>
    </li>
  )

  return(
    <div>
      <div>
        <ul className="nav-link">
          {categoryLinks}
        </ul>
      </div>

      <Switch>
        <Route exact path="/" >
          <Redirect to="/sites" />
        </Route>
        <Route exact path="/sites" component={SitesIndex} />
        <Route exact path ="/sites/new" component={AddNewSiteForm} />
        <Route exact path="/sites/:id" component={SiteShow} />
        <Route exact path="/categories/:id" component={CategoryShow} />
      </Switch>
    </div>
  )

}

export default NavBar
4

3 回答 3

1

您应该包括您遇到问题的组件的代码。

你知道你可以监听名为 useEffect 的特殊反应钩子所做的更改。在您的类别组件中,您可以使用 props.match.params.id 作为 useEffect 依赖项并听取更改

const Categories = (props)=>{
 const id = props.match.params.id;
useEffect(()=>{
  //do something 
},[id])                     // This is where the react listens the changes

}
于 2021-07-01T00:57:35.493 回答
0

问题

您没有包含有问题的代码,即SiteShowandCategoryShow但我怀疑它们都没有对id路由匹配参数值的更改做出反应。

解决方案

在两者中SiteShowCategoryShow使用useEffect依赖于id路由匹配参数的钩子来更新任何状态,获取任何新数据等。

import { useParams } from 'react-router-dom';

...

const { id } = useParams();

useEffect(() => {
  console.log('Route id updated', id);
  // logic to handle the id updating
}, [id]);

如果您仍在使用基于类的组件,请告诉我,我可以更新此用例的答案。

关于使用的小点Switch,您应该将路线从更具体的路径排序到不太具体的路径,这样您就不需要exact在每条路线上指定道具。例如,“/sites/new”比“/sites/:id”更具体,比“/sites”更具体。Redirect也不会也不应该被包裹在Route. 如果您需要从特定路径重定向,请使用该from道具。

<Switch>
  <Route path ="/sites/new" component={AddNewSiteForm} />
  <Route path="/sites/:id" component={SiteShow} />
  <Route path="/sites" component={SitesIndex} />
  <Route path="/categories/:id" component={CategoryShow} />
  <Redirect to="/sites" />
</Switch>
于 2021-07-01T00:39:22.487 回答
0

我最终使用 useLocation 在类别组件上解决了这个问题

const CategoryShow = (props) =>{
  let location = useLocation();
  const [category, setCategory] = useState( {sites: []})

  const fetchCategory = async() => {
    try {
      const categoryId = props.match.params.id
      const response = await fetch(`/api/v1/categories/${categoryId}`)
      if(!response.ok) {
        const errorMessage = `${response.status} (${response.statusText})`
        const error = new Error(errorMessage)
        throw(err)
      }
      const categoryData = await response.json()
      setCategory(categoryData.category)
    } catch (err) {
      console.error(`Error in fetch: ${err.message}`)
      setCategory(null)
    }
  }

  useEffect(() =>{
    fetchCategory()
  },[location.pathname])



  if(!category) {
    return(
    <div>
      <h1>That category could not be found!</h1>
      <img src={"https://error404.fun/img/full-preview/1x/9.png"} height="100%" alt="Page Not Found" />
    </div>
    )
  }

  const siteTiles = category.sites.map(site =>{
    return(
      <SiteTile
      key = {site.id}
      site = {site}
      />
    )
  })

  return(
    <div>
      <h1>{category.name}</h1>
      {siteTiles}
    </div>
  )
}

export default CategoryShow
于 2021-07-01T16:55:34.890 回答