在反应中的 url 更改上重新渲染相同的组件

Posted

技术标签:

【中文标题】在反应中的 url 更改上重新渲染相同的组件【英文标题】:Re-render same component on url change in react 【发布时间】:2019-02-14 13:36:48 【问题描述】:

我有一个路由,它接受一个 id 并为每个 id 呈现相同的组件,例如: <Route path='/:code' component=Card/>

现在,我在 Link 标记中将 id 传递给组件。现在 Card 组件根据传递的 id 获取更多详细信息。但问题是它只为一个 id 呈现,并且如果我单击返回并转到下一个 id 则不会更新。我搜索并发现 componentsWillReceiveProps 可以使用,但在最近的 React 版本中它已被弃用。那么如何做到这一点呢?

【问题讨论】:

***.com/questions/38915066/…的可能重复 【参考方案1】:

将当前位置作为组件的关键可以解决问题。

<Route path='/:code' component=(props) => <Card ...props key=window.location.pathname/>/>

【讨论】:

【参考方案2】:

我刚刚遇到了类似的问题。我认为您将更新/重新渲染和重新安装混为一谈。 This react 生命周期方法的图表在我处理它时帮助了我。

如果你的问题和我的一样,你有一个类似的组件

class Card extend Component 
  componentDidMount() 
    // call fetch function which probably updates your redux store  
  

  render () 
    return // JSX or child component with ...this.props used, 
           // some of which are taken from the store through mapStateToProps
  

当您第一次点击挂载该组件的 url 时,一切正常,然后,当您访问使用相同组件的另一条路线时,没有任何变化。那是因为组件没有被重新挂载,它只是被更新,因为一些道具发生了变化,至少this.props.match.params正在发生变化。

但是当组件更新时不会调用componentDidMount()(参见上面的链接)。所以你不会获取新数据并更新你的 redux 存储。您应该添加一个componentDidUpdate() 函数。这样,您可以在 props 更改时再次调用您的获取函数,而不仅仅是在最初安装组件时。

componentDidUpdate(prevProps) 
  if (this.match.params.id !== prevProps.match.params.id) 
    // call the fetch function again
  

查看 react documentation 了解更多详情。

【讨论】:

【参考方案3】:

我实际上想出了另一种方法。

我们将从您的示例代码开始:&lt;Route path='/:code' component=Card/&gt;

您想要做的是让 &lt;Card&gt; 成为一个包装器组件,最好是功能性(我认为它实际上不需要任何状态)并通过传递您的道具来渲染您想要渲染的组件使用...props,以便它获取路由器属性,但重要的是给它一个key 属性,这将迫使它从头开始重新渲染

例如,我有一些看起来像这样的东西:

<Route exact=false path="/:customerid/:courierid/:serviceid" component=Prices />

我希望我的组件在 URL 更改时重新呈现,但仅在 customerid 或 serviceid 更改时。所以我把Prices 做成这样的功能组件:

function Prices (props) 
    const matchParams = props.match.params;
    const k = `$matchParams.customerid-$matchParams.serviceid`;
    console.log('render key (functional):');
    console.log(k);
    return (
        <RealPrices ...props key=k />
    )

请注意,我的密钥只考虑了 customerid 和 serviceid - 当这两个更改时它会重新呈现,但当 courierid 更改时它不会重新呈现(如果需要,只需将其添加到密钥中)。而我的RealPrices 组件的好处是仍然保留了所有路由道具,例如历史、位置、匹配等。

【讨论】:

【参考方案4】:

在 React Router v4 中,Router 修复问题后添加 Switch 标签

【讨论】:

这是什么意思? 这没有任何意义【参考方案5】:

如果您正在寻找使用钩子的解决方案。

如果您从某个 API 获取数据,那么您可以将该调用封装在 useEffect 块中,并将 history.location.pathname 作为参数传递给 useEffect

代码:

import  useHistory  from "react-router";

    
const App = () => 
  const history = useHistory();

  useEffect(() => 
    //your api call here
  , [history.location.pathname]);
;

来自react-routeruseHistory 钩子将给出路径名,因此每次更改(url)时都会调用useEffect

【讨论】:

以上是关于在反应中的 url 更改上重新渲染相同的组件的主要内容,如果未能解决你的问题,请参考以下文章

在反应中更改状态时组件不会重新渲染

如何在反应原生的子组件上重新渲染父组件?

即使道具没有改变,为啥还要对重新渲染组件做出反应?

属性更改时如何重新渲染反应组件

反应我必须重新渲染父母才能重新渲染孩子吗?

使用 Lodash.remove 通过 Vuex 突变更改状态不会触发我的 Vue 组件中的反应式重新渲染