路由参数更改时,组件不会重新安装

我正在使用react-router开发一个React应用程序。我有一个项目页面,其URL如下:

myapplication.com/project/unique-project-id

当项目组件加载时,我从componentDidMount事件触发了对该项目的数据请求。我现在遇到一个问题,即如果我直接在两个项目之间切换,那么只有id会这样改变...

myapplication.com/project/982378632
myapplication.com/project/782387223
myapplication.com/project/198731289

componentDidMount不会再次触发,因此不会刷新数据。我是否应该使用另一个生命周期事件来触发我的数据请求,或者使用其他策略来解决此问题?

Davaid阳光小卤蛋2020/03/12 17:32:57

react-router 损坏,因为必须在任何位置更改时重新安装组件。

我设法找到了一个修复此错误的方法:

https://github.com/ReactTraining/react-router/issues/1982#issuecomment-275346314

简而言之(有关完整信息,请参见上面的链接)

<Router createElement={ (component, props) =>
{
  const { location } = props
  const key = `${location.pathname}${location.search}`
  props = { ...props, key }
  return React.createElement(component, props)
} }/>

这将使其在任何URL更改时重新安装

理查德十三2020/03/12 17:32:57

如果在更改路线时确实需要重新安装组件,则可以将唯一键传递给组件的key属性(该键与您的路径/路由相关联)。因此,每当路线更改时,密钥也会更改,从而触发React组件卸载/重新安装。我从这个答案中得到了主意

小小2020/03/12 17:32:57

根据@ wei,@ Breakpoint25和@PaulusLimma的回答,我为制作了此替换组件<Route>当URL更改时,这将重新安装页面,迫使页面中的所有组件都被创建并重新安装,而不仅仅是重新呈现。所有componentDidMount()其他所有启动钩子也会在URL更改时执行。

这个想法是key在URL更改时更改组件属性,这将迫使React重新安装组件。

您可以将其用作的替代产品<Route>,例如:

<Router>
  <Switch>
    <RemountingRoute path="/item/:id" exact={true} component={ItemPage} />
    <RemountingRoute path="/stuff/:id" exact={true} component={StuffPage} />
  </Switch>
</Router>

<RemountingRoute>组件的定义如下:

export const RemountingRoute = (props) => {
  const {component, ...other} = props
  const Component = component
  return (
    <Route {...other} render={p => <Component key={p.location.pathname + p.location.search}
                                              history={p.history}
                                              location={p.location}
                                              match={p.match} />}
    />)
}

RemountingRoute.propsType = {
  component: PropTypes.object.isRequired
}

这已经通过React-Router 4.3进行了测试。

SamStafan2020/03/12 17:32:57

如果你有:

<Route
   render={(props) => <Component {...props} />}
   path="/project/:projectId/"
/>

在React 16.8及更高版本中,使用hooks可以执行以下操作:

import React, { useEffect } from "react";
const Component = (props) => {
  useEffect(() => {
    props.fetchResource();
  }, [props.match.params.projectId]);

  return (<div>Layout</div>);
}
export default Component;

在此,fetchResource只要props.match.params.id更改,您就只会触发一个新呼叫

达蒙理查德2020/03/12 17:32:57

这是我的答案,与上述类似,但有代码。

<Route path="/page/:pageid" render={(props) => (
  <Page key={props.match.params.pageid} {...props} />)
} />