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

React Router V6修改URL路径触发应用重载,求原因

问题描述

用Create React App创建的应用,基于React Router Dom v6和Redux Toolkit开发。正常通过NavLink导航时页面无刷新,但在浏览器地址栏直接输入指定路径(如/starred)或刷新当前页面时,整个应用会重载,导致Redux状态被重置。临时改用Hash Router后,输入当前页面的相同URL仍会触发重载。

相关代码

Index.js

const container = document.getElementById('root');
const root = createRoot(container);

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route path='/' element={<App/>}>
      <Route index path='starred' element={<ArticleList/>}/>
      <Route index path='latest' element={<ArticleList/>}/>
    </Route>
  )
)

root.render(
  <Provider store={store}>
    <RouterProvider router={router}/>
  </Provider>
);

App.js

function App() {
  const Outlet = useOutlet();
  const theme = useSelector(state => state.theme.getTheme);

  return (
    <div className='App' data-theme={theme}>
       <Header/>
       { Outlet ?? <ArticleList/>}
       <Footer/>
    </div>
  );
}

Header.js(使用NavLink实现无刷新导航)

export default function Header() {
const activeStyle = {
    color: 'coral',
};
const inactiveStyle = {
    'fontSize':'small',
}

const matches = useMatches();
return (
    <div className='header-nav'>
        <div>
            <NavLink to='/'>
                <i className="fa-brands fa-3x fa-hacker-news" ></i>
            </NavLink>
        </div>
        <div>
            <h1> Hacker News </h1>
        </div>
        <div className='header-space'>
            <span>
            <NavLink 
                style={({ isActive }) =>
                matches.length === 1 || isActive ? activeStyle : inactiveStyle
                }
                to='latest' end>latest</NavLink>
            </span>  |   
            <span>
            <NavLink
                style={({ isActive }) =>
                isActive ? activeStyle : inactiveStyle
                }
                to='starred'>starred</NavLink>

            </span>
       </div>
        <ToggleTheme/>
    </div>
)
}

ArticleList.js

export default function ArticleList() {
const {
    data: articleIds, 
} = useGetIdsQuery();

const [index, setIndex] = useState(0);
const [starredIndex, setStarredIndex] = useState(0);
const location = useMatches();
const starredIds = useSelector(articlesSelector.selectIds);
const isStarred = location.find(({pathname}) => pathname === '/starred')?.pathname === '/starred';
const displayArticles = isStarred ? starredIds?.slice(starredIndex, starredIndex + 12) : articleIds?.slice(index, index + 12);

const onClickHandler = () => {
    if(displayArticles.length < 12) return; 
    if(isStarred) {
        const nextPage = starredIndex + 12;
        setStarredIndex(nextPage);
    }
    const nextPage = index + 12;
    setIndex(nextPage)

}
return (
    <div>
        <ol className="list-groupMine">
        {displayArticles?.map((id)=><Article key={id} id={id}/>)}
        </ol> 
        <div className='show-more'>
            <button className='showMoreButton' onClick={onClickHandler}> show more </button>
        </div>
    </div>
)
}

Article.js

export default function Article({id}){
const { data } = useGetArticleQuery(id ?? skipToken);
const { url, title, score, kids, by } = data?.entities[id] ?? {};
const domain =  url ? new URL(url) : undefined;
const dispatch = useDispatch();
const selectEntities = useSelector(articlesSelector.selectEntities); 
const isSaved = selectEntities[id]?.saved === 'saved' ? 'saved' : 'save';
const onClickHandler = () => {
    if(selectEntities[id]) {
        return dispatch(removeSaved(id));
    }
    dispatch(addSaved({...data?.entities[id], saved:'saved' }));
}

return(
    <div className="spacer">
        <div>
            <span >
                <a href={url} style={{'fontFamily': 'monospace'}} target="_blank" rel="noopener noreferrer">{title}</a>
            </span>
            <span>
                <a className="extra-inline-style" href={url} style={{ 'color':'grey',}} target="_blank" rel="noopener noreferrer">{`(${domain?.host.replace('www.','') ?? ''})`}</a>     
            </span>
        </div>
        <div className="subtext">
        <p>
            {`${score} points by ${by} `}
            |{` ${kids?.length ?? 0} comments `}
            | {isSaved === 'saved'? <BsStarFill style={{'color': 'orange'}} onClick={onClickHandler}/> : <BsStar  onClick={onClickHandler}/> }
            <span>{' ' + isSaved}</span>
            </p>

        </div>
    </div>
)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 20:50:35