You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React路由未更新问题:点击导航仅URL变化页面不刷新

问题修复方案

核心问题分析

  1. 重复嵌套BrowserRouter:Navbar组件内部额外包裹了<BrowserRouter>,但App组件已经存在根Router。嵌套的Router会导致Link的导航仅在内部Router生效,根Router无法感知路由变化,因此页面不会重新渲染。
  2. 未监听props更新:News组件仅在componentDidMount中初始化数据,当路由切换导致category等props变化时,没有触发重新获取数据的逻辑,只有刷新页面重新挂载组件才会更新内容。

修复步骤

1. 移除Navbar中的重复Router

修改Navbar.js,去掉多余的<BrowserRouter>包裹,确保所有路由相关组件处于同一个Router上下文:

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

export default class Navbar extends Component {
  render() {
    return (
      <nav className="navbar navbar-expand-lg bg-body-tertiary" data-bs-theme="dark">
        <div className="container-fluid ">
          <Link className="navbar-brand" to="/">News Letter</Link>
          <button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
            <span className="navbar-toggler-icon"></span>
          </button>
          <div className="collapse navbar-collapse" id="navbarSupportedContent">
            <ul className="navbar-nav me-auto mb-2 mb-lg-0">
              <li className="nav-item"> <Link to="/general" className="nav-link" >Home</Link></li>
              <li className="nav-item"> <Link to="/business" className="nav-link">Business</Link></li>
              <li className="nav-item"> <Link to="/entertainment" className="nav-link">Entertainment</Link></li>
              <li className="nav-item"> <Link to="/health" className="nav-link">Health</Link></li>
              <li className="nav-item"> <Link to="/science" className="nav-link">Science</Link></li>
              <li className="nav-item"> <Link to="/sports" className="nav-link">Sports</Link></li>
              <li className="nav-item"> <Link to="/technology" className="nav-link">Technology</Link></li>
              <li className="nav-item"> <Link to="/education" className="nav-link">Education</Link></li>
            </ul>
          </div>
        </div>
      </nav>
    )
  }
}

2. 给News组件添加props变化监听

修改News.js,添加componentDidUpdate方法监听props变化,同时封装数据请求逻辑减少重复代码:

import Loading from './Loading';
import NewsItem from './NewsItem'
import React, { Component } from 'react'

export default class News extends Component {
  constructor() {
    super()
    this.state = {
        articles: [],
        loading: false,
        page: 1,
        totalResults: 0
    }
  }

  async componentDidMount() {
    this.fetchNews();
  }

  // 监听props变化,重新获取数据
  async componentDidUpdate(prevProps) {
    if (prevProps.category !== this.props.category || prevProps.country !== this.props.country) {
      this.setState({ page: 1 });
      await this.fetchNews();
    }
  }

  // 封装数据请求逻辑
  fetchNews = async () => {
    const url = `https://newsapi.org/v2/top-headlines?country=${this.props.country}&category=${this.props.category}&apiKey=71af8e98db3b4e04b13dcfaca6f9ee2a&page=${this.state.page}&pageSize=${this.props.pageSize}`;
    this.setState({ loading: true })
    const data = await fetch(url);
    const parsedData = await data.json();
    this.setState({
      articles: parsedData.articles,
      totalResults: parsedData.totalResults,
      loading: false
    });
  }

  handleNext = async () => {
    if ((this.state.page + 1) > Math.ceil(this.state.totalResults / this.props.pageSize)) return;
    this.setState(prevState => ({ page: prevState.page + 1 }), async () => {
      await this.fetchNews();
    });
  }

  handlePrev = async () => {
    if (this.state.page <= 1) return;
    this.setState(prevState => ({ page: prevState.page - 1 }), async () => {
      await this.fetchNews();
    });
  }

  render() {
    const categoryTitle = this.props.category.charAt(0).toUpperCase() + this.props.category.slice(1);
    return (
      <>
        <div className="container my-3">
          <h1 className='text-center my-5'>Top {categoryTitle} News Headlines :</h1>
          {this.state.loading && <Loading/>}
          <div className="row my-3">
            {!this.state.loading && this.state.articles.map((element) => {
              return <div className="col" key={element.url}>
                <NewsItem imageurl={element.urlToImage} title={element.title} description={element.description} author={element.author} time={element.publishedAt} />
              </div>
            })}
          </div>
        </div>

        <div className="container d-flex justify-content-around my-5">
          <button disabled={this.state.page<=1} type="button" onClick={this.handlePrev} className="btn btn-primary">&larr;Previous </button>
          <button disabled={(this.state.page + 1) > Math.ceil(this.state.totalResults/this.props.pageSize)} type="button" onClick={this.handleNext} className="btn btn-primary">Next &rarr;</button>
        </div>
      </>
    )
  }
}

这里还修复了handlePrev中的page参数错误,同时动态显示分类标题提升用户体验。

3. 优化App路由(可选)

将多个重复路由合并为带参数的路由,减少代码冗余:

import './App.css';
import React, { Component } from 'react'
import Navbar from './components/Navbar'
import News from './components/News';
import {
  BrowserRouter as Router,
  Routes,
  Route,
} from "react-router-dom";

export default class App extends Component {
  render() {
    return (
      <Router>
        <Navbar/>
        <Routes>
          <Route exact path="/" element={<News country="in" category="general" pageSize={6}/>}  />
          <Route exact path="/:category" element={<News country="in" pageSize={6} />}  />
        </Routes>  
      </Router>
    )
  }
}

此时需要给News组件添加路由参数支持(使用withRouter高阶组件),从路由参数中获取分类值。


效果验证

修复后点击导航按钮,URL变化的同时,根Router会匹配到对应路由,News组件会感知到category props的变化,自动重置页面状态并重新请求对应分类的新闻数据,页面无需刷新即可更新内容。

内容的提问来源于stack exchange,提问作者Lakshya Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 22:05:53