React router:如何在param change上更新路由组件?

时间:2018-01-09 01:40:54

标签: reactjs react-router-v4

当url参数更改时,我需要更新两个组件,但其中一个组件位于带有param的路径之外。 App.js中的路由是这样的:

<BrowserRouter>
  <div>
       <Route exact path="/" render={ (props) =>
         <Home products={this.state.products} } 
       />
        <Route path="/products/:product" render={ (props) => 
          <Product {...props} /> } 
        /> 

        <Route path="/"  render={ props => 
            <ProductHistory {...props}/>  }
         /> 
  </div>   

</BrowserRouter> 

始终可见的ProductHistory具有指向产品的链接,例如:

<Link to={`/products/${product.product_id}`}> {product.name}</Link>

在关注此类链接时,使用ComponentWillReceiveProps方法更新Product组件:

componentWillReceiveProps(nextProps) {
    if(nextProps.match.params.product !== this.props.match.params.product){

但是,如何在产品参数更改的同时更新ProductHistory组件?由于它不在/products/:product路线中,因此检查ProductHistory的componentWillReceiveProps中的this.props.match.params.product会产生undefined。 (编辑 - 并且withRouter没有帮助,因为它已经在路线中,但是不同的路线:&#34; /&#34;)

在componentWillReceiveProps中,我可以使用location.pathname检查路径是否以&#34; / product&#34;开头,我可以通过substr(path.lastIndexOf('/') + 1找到该参数。

编辑但我还必须将当前的id参数与下一个产品ID参数进行比较,以避免不必要的更新。但是当点击链接时,当componentWillReceiveProps触发时,网址已经更改,因此location.pathnamenextProps.location.pathname始终匹配,因此会不必要地更新(重复的api调用)。

所以我必须找到一个不同的解决方案 - 以某种方式重新排列路由?我们的想法是,ProductHistory应该始终可见。

2 个答案:

答案 0 :(得分:1)

您可以像这样渲染路线:

<BrowserRouter>
  <div>
  <Switch>
    <Route exact path="/" render={ (props) =>
      <Home products={this.state.products} } 
    />
    <Route path="/products/:product" render={ (props) => 
      <Product {...props} /> } 
    /> 
  </Switch>
  <ProductHistory />
  </div>
</BrowserRouter>

然后在 ProductHistory 类中使用withRouter HOC

  

您可以访问历史对象的属性和最近的属性   通过 withRouter 更高阶组件路由的匹配。的 withRouter   将更新的匹配,位置和历史道具传递给包装   组件何时呈现。

示例:

class ProductHistory extends Component { ... }

export default withRouter(ProductHistory);

或使用装饰器

@withRouter
export default class ProductHistory extends Component { ... }

通过这种方式,您可以通过以下道具访问匹配,位置和历史记录:

this.props.match
this.props.location
this.props.history

答案 1 :(得分:1)

对于任何陷入困境的人,钩子提供了一种新的解决方案,其形式为useRouteMatch中的react-router-dom

您可以像JoãoCunha的示例一样布置代码,其中ProductHistory不在Route中包装。如果ProductHistory在产品的Route之外,则所有正常的路由信息​​似乎都会给出错误的答案(我认为这可能是withRouter出现问题的地方(对João解决方案的答复),但这是因为它不了解产品路线路径规格。与大多数MVC路由器略有不同,React-router-dom不会计算预先匹配的路由,它将通过每个Route路径规范测试您所在的路径并生成特定的路由匹配信息Route下的组件。

因此,可以这样考虑:在ProductHistory组件中,您使用useRouteMatch来测试路由是否与可从中提取所需参数的路径规范匹配。例如

import { useRouteMatch } from 'react-router-dom';
const ProductHistory = () => {
  const { params: { product } } = useRouteMatch("/products/:product");
  return <ProductList currentProduct={product || null} />;
};

这将使您能够对可能适用于产品的多个URL进行测试和匹配,从而提供了非常灵活的解决方案!