React Router Link 正在更改 URL,但组件保持不变

0 javascript reactjs react-router react-router-dom

所以我遇到了一个问题,当点击链接时,URL 正在改变,但视图保持不变,直到我刷新页面。

我研究了许多解决方案,唯一有效的方法是强制重新加载我不想要的页面,因为 React 是一个 SPA(单页应用程序)。我已经尝试过 history.push() 和 Link ,但输出保持不变。如果您需要查看其他文件,这是我的仓库

应用程序.js

import React from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';

import Header from './components/header/header.component';

import HomePage from './pages/homepage/homepage.component';
import Details  from './pages/detail/detail.component';

import './App.scss';

const App = () => (
    <Router>
        <Header />
        <Switch>
            <Route exact path="/" component={HomePage} />
            <Route path="/:name" component={Details}/>
        </Switch>
    </Router>
);
Run Code Online (Sandbox Code Playgroud)

细节组件

import React from 'react';

import LinkButton from '../../components/link-button/link-button.component';

import './detail.style.scss';

class Details extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            borders: [],
            country: '',
        };
    }

    async componentDidMount() {
        const { name } = this.props.match.params;
        fetch(`https://restcountries.eu/rest/v2/name/${name}?fullText=true`)
            .then((res) => res.json())
            .then((data) => {
                this.setState({ country: data[0] });
                return data[0].borders;
            })
            .then((country) => {
                for (let i = 0; i < country.length; i++) {
                    if (i > 2) break;
                    fetch(`https://restcountries.eu/rest/v2/alpha/${country[i]}`)
                        .then((res) => res.json())
                        .then((data) =>
                            this.setState({ borders: [...this.state.borders, data.name] })
                        );
                }
            });
    }

    render() {
        const { country, borders } = this.state;
        if (country !== '') {
            return (
                <div className="detail-container">
                    <div className="detail-back-btn">
                        <LinkButton value="/">
                            <i className="fas fa-long-arrow-alt-left icon"></i> Back
                        </LinkButton>
                    </div>
                    <div className="detail-stats">
                        <img className="detail-flag" alt="Flag" src={country.flag} />
                        <div className="detail-text-container">
                            <h1 className="heading">{country.name}</h1>
                            <div className="detail-text">
                                <div className="left">
                                    <p className="text">
                                        Native Name: <span>{country.nativeName}</span>
                                    </p>
                                    <p className="text">
                                        Population:
                                        <span>{country.population.toLocaleString()}</span>
                                    </p>
                                    <p className="text">
                                        Region: <span>{country.region}</span>
                                    </p>
                                    <p className="text">
                                        Sub Region: <span>{country.subregion}</span>
                                    </p>
                                    <p className="text">
                                        Capital: <span>{country.capital}</span>
                                    </p>
                                </div>
                                <div className="right">
                                    <p className="text">
                                        Top Level Domain: <span>{country.topLevelDomain}</span>
                                    </p>
                                    <p className="text">
                                        Currencies:{' '}
                                        <span>
                                            {country.currencies.map((e) => e.name).join(', ')}
                                        </span>
                                    </p>
                                    <p className="text">
                                        Languages:{' '}
                                        <span>
                                            {country.languages.map((e) => e.name).join(', ')}
                                        </span>
                                    </p>
                                </div>
                            </div>

                            <div className="border">
                                <p className="border-text">Border Countries:</p>
                                <span className="border-btn">
                                    {borders.map((border, index) => (
                                        <LinkButton key={index} value={border}>
                                            {border}
                                        </LinkButton>
                                    ))}
                                </span>
                            </div>
                        </div>
                    </div>
                </div>
            );
        } else return null;
    }
}

export default Details;

Run Code Online (Sandbox Code Playgroud)

链接按钮组件

import React from 'react';
import { Link, withRouter } from 'react-router-dom';

import './link-button.style.scss';

//this is the brute force reload solution
//which is working, but i need a better approach
function refreshPage() {
    setTimeout(() => {
        window.location.reload(false);
    }, 0);
    console.log('page to reload');
}

const LinkButton = ({ value, children, history, match, location }) => {
    console.log(history, match, location);
    return (
        <Link to={value} onClick={refreshPage}>
            <button
                className="link-btn"
                value={value}
            >
                {children}
            </button>
        </Link>
    );
};

export default withRouter(LinkButton);

Run Code Online (Sandbox Code Playgroud)

Bri*_*son 6

您看到的是从一个 URL 到另一个 URL 的更改,但它们都匹配相同的Route路径,因此react-router不会重新安装组件。这是有意为之,如果您考虑Switch组件的用途,这也是有道理的。

例如:“/a”和“/b”都匹配<Route path="/:name" component={Details}/>。因此,当从一个更改为另一个时,没有理由react-router重新安装该Details组件,因为它仍然匹配。

为了完成你想要做的事情,你需要监听路由参数(nameprop)中的更新。

一种策略是使用componentDidUpdate生命周期方法检查值是否已更改:

componentDidUpdate(prevProps) {
  if (this.props.match.params.name !== prevProps.match.params.name) {
    // Refetch your data here because the "name" has changed.
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,componentDidUpdate不会在初始渲染时调用,因此您将需要两种生命周期方法。但是,你可以拿出你的fetch电话到它自己的方法,这样既您componentDidMountcomponentDidUpdate可以重复使用相同的代码。

对于那些使用带有钩子的功能组件的人来说,这个聆听过程会变得更容易一些。使用useEffect带有路由参数的钩子作为依赖项将完成与类版本中的两个生命周期方法相同的事情。

const { name } = useParams();

useEffect(() => {
  // Fetch data
}, [name]);
Run Code Online (Sandbox Code Playgroud)