如何使用 react-router-dom 卸载路由更改上的组件而不是重新渲染 [重复]

Posted

技术标签:

【中文标题】如何使用 react-router-dom 卸载路由更改上的组件而不是重新渲染 [重复]【英文标题】:How to remount a componet on Route change using react-router-dom instead of re-rendering [duplicate] 【发布时间】:2019-11-14 07:17:51 【问题描述】:

更新:这个问题与重复问题有何不同?

这里我们有相同的组件被 2 个不同的路由渲染。 在另一个问题中,OP 想知道如何重新安装一个被相同的路由一遍又一遍渲染的组件,只需更改路由参数即可。

链接:Component does not remount when route parameters change


我在ProductSearch 组件上有以下情况。

它可能被两个不同的<Route>'s渲染:

它们都显示ProductSearch页面,并带有相应产品的过滤器。

<Route exact path='/category/:slug' component=ProductSearchContainer/>
<Route exact path='/search/:slug' component=ProductSearchContainer/>

第一个发生在您点击产品类别菜单时:

因此结果已经在特定类别中。 然后它会显示特定于该产品类别的过滤器。

第二个发生在您使用带有一些文本的 SearchBar 搜索产品时。

您还没有进入某个类别,因此它只显示通用过滤器,例如PriceBrandRating 等...

问题在于,如果您直接从一条路由更改为另一条,组件将简单地重新渲染。我希望它能够更好地重新安装,因为这样我就可以重新开始我选择的过滤器活动状态和产品列表等...

例如,这会发生在以下场景中:

    用户点击分类导航按钮Phones ProductSearch 组件为 Phones 类别呈现 用户过滤了一堆东西并决定进行文本搜索并从头开始 用户搜索some random text ProductSearch 被重新渲染(使用第二条路线)但如果我不重置所有过滤状态将保持不变。

注意下面 GIF 中的 URL 变化:

问题:

有没有办法确保我的组件在这种情况下更改为不同的路由时会重新安装?

CodeSandbox 示例:

https://codesandbox.io/s/react-routerremountonroutechangeso-881m3


完整代码:index.js

(如果 CodeSandbox 链接不再可用)

import React,  useEffect  from "react";
import ReactDOM from "react-dom";
import  BrowserRouter as Router, Link, Switch, Route  from "react-router-dom";

import "./styles.css";

function App() 
  return (
    <Router>
      <AllRoutes />
    </Router>
  );


function AllRoutes(props) 
  return (
    <Switch>
      <Route exact path="/" component=Home />
      <Route exact path="/category/:slug" component=ProductSearch />
      <Route exact path="/search/:slug" component=ProductSearch />
    </Switch>
  );


function Home(props) 
  return (
    <div>
      <div>I am Home</div>
      <div>
        <Link to="/category/phones">Phones</Link>
      </div>
    </div>
  );


function ProductSearch(props) 
  console.log("Rendering ProductSearch...");

  useEffect(() => 
    console.log("ProductSearch mounted...");
    return () => console.log("ProductSearch unmounted...");
  , []);

  // useEffect(() => 
  //   console.log('Inside useEffect for slug...');
  //   console.log(props.match.params.slug);
  // ,[props.match.params.slug]);

  return (
    <div>
      <div>I am ProductSearch</div>
      <div>
        <Link to="/">Home</Link>
      </div>
      <div>
        <Link to="/search/phoneModelXYZ">Search for Phone XYZ</Link>
      </div>
    </div>
  );


const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

【问题讨论】:

Component does not remount when route parameters change 的可能重复项 - 其中一个答案显示了一种强制重新安装的方法,其他答案解释了为什么最好不要这样做。 【参考方案1】:

所以这就是我最终做的事情:

通过在 Route 中为渲染组件提供一个键,您可以使其重新挂载而不是重新渲染。

<Route exact path='/category/:slug' render=(routeProps)=>
  <ProductSearch ...routeProps key=routeProps.match.params.slug/>
/>
<Route exact path='/search/:slug' render=(routeProps)=>
  <ProductSearch ...routeProps key='search'/>
/>

现在我得到以下结果:

【讨论】:

以上是关于如何使用 react-router-dom 卸载路由更改上的组件而不是重新渲染 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

尝试导入错误:“Switch”未从“react-router-dom”导出

./src/App.js 尝试导入错误:“Switch”未从“react-router-dom”导出

React漫漫学习路之 React Router

使用 react-router-dom 时如何避免“功能组件不能被赋予 refs”?

如何使用 react-router-dom 获取当前 URL 的来源?

如何正确使用 react-router-dom 中的 useHistory()?