【问题标题】:React Router Link changes URL but doesn't render Component - Rest Countries APIReact Router Link 更改 URL 但不呈现组件 - 休息国家 API
【发布时间】:2021-08-31 11:28:07
【问题描述】:

我正在根据前端管理员 (https://www.frontendmentor.io/challenges/rest-countries-api-with-color-theme-switcher-5cacc469fec04111f7b848ca) 提出的其他国家/地区 API 挑战构建一个应用程序。我遇到了一个问题。当点击 countryDetail.js 中的路由器链接时,url 会发生变化,但除非刷新页面,否则组件不会重新渲染。

CountryDetails.js

import React, { useState, useEffect } from "react";
import axios from "axios";
import {Link} from "react-router-dom";
import {CountryDetailStyles, ImgContainer, CountryInfo, CountryInfoDetails, CountryDetailsWrapper, CountryInfoDetailsInner, CountryBorders, LinkWrapper} from "../styles/CountryDetailStyles";

function CountryDetail({match, history}) {

  const [item, setItem] = useState([]);
  const [allCountries, setAllCountries] = useState([]);

  useEffect(() => {
     fetchItem();
     setBorderCountries();
  }, []);

  const fetchItem = async () => {
    const response = await axios.get(`https://restcountries.eu/rest/v2/name/${match.params.name}?fullText=true`);
    setItem(response.data)
  }

  const setBorderCountries = async () => {
    const response = await axios.get(`https://restcountries.eu/rest/v2/all`);
    setAllCountries(response.data)
  }

  // get borders full name using alpha3code
  const getBorderCountryName = (allCountries, border) => {
    const matchingCountry = allCountries.find(country => {
      return country.alpha3Code === border;
    })

     return matchingCountry.name;
  }
    
  return (
       <CountryDetailStyles>
           <Link className="country-links" to={"/"}>
             <LinkWrapper>
             <p><i className="fas fa-arrow-left"></i>Go Back</p>
             </LinkWrapper>
             </Link>
           {
            item.length > 0 && item.map(i => (   
               <CountryDetailsWrapper>           
               <ImgContainer flag={i.flag}>
               </ImgContainer>
               <CountryInfo>
                   <h1>{i.name}</h1>
                   <CountryInfoDetails>
                       <CountryInfoDetailsInner>
                       <p><span>Native Name: </span>{i.nativeName}</p>
                       <p><span>Population: </span>{i.population.toLocaleString()}</p>
                       <p><span>Region: </span>{i.region.length > 0 ? i.region : 'N/A'}</p>
                       <p><span>Sub Region: </span>{i.subregion.length > 0 ? i.subregion : 'N/A'}</p>
                       <p><span>Capital: </span>{i.capital.length > 0 ? i.capital : 'N/A'}</p>
                       </CountryInfoDetailsInner>
                       <CountryInfoDetailsInner className="second">
                       <p><span>Top Level Domain: </span>{i.topLevelDomain}</p>
                       <p><span>Currencies: </span>{i.currencies[0].name}</p>
                       <p><span>Languages: </span>{i.languages.map(lang => lang.name).join(", ")}</p>
                       </CountryInfoDetailsInner>
                   </CountryInfoDetails>
                   <CountryBorders>
                       <p><span>Border Countries:</span></p>
                    {allCountries.length > 0 && i.borders.map(border => {
                      const borderName = getBorderCountryName(allCountries, border);
                      return (<Link to={`/country/${borderName.toLowerCase()}`}><button>{borderName}</button></Link>)
                    })}
                   </CountryBorders>
               </CountryInfo>
               </CountryDetailsWrapper>
           ))
           }
        </CountryDetailStyles>
  )
}

export default CountryDetail;

App.js

import './App.css';
import { ThemeProvider } from 'styled-components';
import { lightTheme, darkTheme } from './styles/themes';
import { GlobalStyles } from './styles/global';
import { useState } from 'react';
import Navbar from './components/Navbar';
import { useDarkMode } from './hooks/useDarkMode';
import CountryList from './components/CountryList';
import CountryDetail from './components/CountryDetail';
import {Route} from "react-router-dom";


function App() {
  const [theme, toggleTheme] = useDarkMode();
  const themeMode = theme === 'dark' ? darkTheme : lightTheme;

  return (
    <div className="App">
      <ThemeProvider theme={themeMode}>
        <GlobalStyles />
        <Navbar navTheme={theme} toggleTheme={toggleTheme} />
        <Route exact path="/" component={CountryList} />
        <Route exact path="/country/:name" component={CountryDetail} />
      </ThemeProvider>
    </div>
   
  );
}

export default App;

索引.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';

ReactDOM.render(
  <BrowserRouter>
    <App />
    </BrowserRouter>,
  document.getElementById('root')
);

 
reportWebVitals();

【问题讨论】:

  • 您可以尝试将您的路线包装在&lt;Switch&gt; 中吗?
  • 不幸的是没有工作:(
  • 第二条路线上应该有“精确”吗?
  • 删除了确切的,仍然没有工作:(

标签: javascript reactjs api react-hooks react-router-dom


【解决方案1】:

问题

问题似乎是您已经"/country/:name" 路径上并且正在点击访问另一个 em> 国家。路由器正确更新了地址栏中的 URL,但由于 CountryDetail 已经挂载,它忽略了重新计算 itemallCountries 状态。这是因为useEffect 钩子只在组件挂载时运行一次。

解决方案

name 参数(match.params.name实际上是 GET 请求的依赖项,它应该添加到 useEffect 挂钩的依赖项数组中。

useEffect(() => {
 fetchItem();
 setBorderCountries();
}, [match.params.name]);

const fetchItem = async () => {
  const response = await axios.get(
    `https://restcountries.eu/rest/v2/name/${match.params.name}?fullText=true`
  );
  setItem(response.data);
}

建议

似乎allCountries 没有 有这种依赖关系,所以我建议将它拆分成它自己的带有空依赖关系数组的useEffect 钩子,这样你只在组件挂载时获取这个数据一次。

useEffect(() => {
 setBorderCountries();
}, []);

useEffect(() => {
 fetchItem();
}, [match.params.name]);

【讨论】:

  • 像魅力一样工作 :) 谢谢!
猜你喜欢
  • 2019-11-23
  • 1970-01-01
  • 2021-08-10
  • 2021-05-14
  • 1970-01-01
  • 1970-01-01
  • 2019-11-30
  • 2020-05-06
  • 2018-05-20
相关资源
最近更新 更多