React 不会在路由参数更改或查询更改时重新加载组件数据

IT技术 javascript reactjs react-router react-router-v4 react-router-dom
2021-01-21 02:12:23

我有一个带有链接的“主页”组件,当您单击链接时,产品组件将与产品一起加载。我还有另一个始终可见的组件,显示“最近访问过的产品”的链接。

这些链接在产品页面上不起作用。单击链接时 url 会更新,并且会发生渲染,但产品组件不会随新产品一起更新。

请参阅此示例: Codesandbox 示例

以下是 index.js 中的路由:

<BrowserRouter>
  <div>
    <Route
      exact
      path="/"
      render={props => <Home products={this.state.products} />}
    />

    <Route path="/products/:product" render={props => <Product {...props} />} />

    <Route path="/" render={() => <ProductHistory />} />

    <Link to="/">to Home</Link>
  </div>
</BrowserRouter>;

ProductHistory 中的链接如下所示:

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

所以他们匹配Route path="/products/:product".

当我在产品页面上并尝试遵循 ProductHistory 链接时,URL 会更新并呈现,但组件数据不会更改。在 Codesandbox 示例中,您可以取消注释 Product components render function 中的警报,以查看它在您点击链接时呈现,但没有任何react。

不知道是什么问题...能不能解释一下问题并找到解决办法?那很好啊!

4个回答

与 一起componentDidMount,您还需要页面中实现componentWillReceivePropsor 使用getDerivedStateFromProps(从 v16.3.0 开始),Products因为相同的组件已re-rendered 更新,params并且not re-mounted当您更改路由参数时,这是因为 params 作为props传递给组件并且props更改, React 组件重新渲染而不是重新安装。

编辑:从 v16.3.0 开始用于getDerivedStateFromProps基于 props 设置/更新状态(无需在两种不同的生命周期方法中指定它)

static getDerivedStateFromProps(nextProps, prevState) {
   if (nextProps.match.params.product !== prevState.currentProductId){
      const currentProductId = nextProps.match.params.product
      const result = productlist.products.filter(obj => {

        return obj.id === currentProductId;

      })
     return {

        product: result[0],
        currentId: currentProductId,
        result

      }
  }
  return null;
}

在 v16.3.0 之前,您将使用 componentWillReceiveProps

componentWillReceiveProps(nextProps) {
    if (nextProps.match.params.product !== this.props.match.params.product) {
      const currentProductId = nextProps.match.params.product
      const result = productlist.products.filter(obj => {

        return obj.id === currentProductId;

      })
      this.setState({

        product: result[0],
        currentId: currentProductId,
        result

      })
    }
  }

工作代码沙盒

我尝试了getDerivedStateFromProps解决方案。但它没有用。似乎getDerivedStateFromProps只有在 mount 上触发一次。
2021-03-21 02:12:23
这为我指明了正确的方向,感谢您的出色回答。
2021-03-26 02:12:23
@BastianVoigt:您可以在 react +16.3 中使用新生命周期方法的集成getDerivedStateFromPropscomponentDidUpdate本答案所述
2021-03-27 02:12:23
componentWillReceiveProps 现在已弃用。但是你还能怎么做呢?
2021-04-09 02:12:23
@arvinsim,不正确,getDerivedStateFromPRops 会在初始安装以及其他所有更新时触发。这个 API 在 16.4 中也有变化。我将更新我的答案以包含该更改
2021-04-09 02:12:23

由于产品组件已经加载,它不会重新加载。您必须在以下组件方法中处理新产品 ID

componentWillReceiveProps(nextProps) {
if(nextProps.match.params.name.product == oldProductId){
  return;
}else {
 //fetchnewProduct and set state to reload
}

使用最新版本的 react(16.3.0 以后)

static getDerivedStateFromProps(nextProps, prevState){
   if(nextProps.productID !== prevState.productID){
     return { productID: nextProps.productID};
  } 
  else {
     return null;
  }
}

componentDidUpdate(prevProps, prevState) {
  if(prevProps.productID !== this.state.productID){
     //fetchnewProduct and set state to reload
  }
}
是的,但是当当前的 productID (this.props.productID) 与我所在州的不同时,我想重新加载,你不觉得吗?
2021-03-16 02:12:23
@BastianVoigt。没错,这就是上述条件的作用。当前的 productID(this.props.producID) 将具有我们在 state 变量中所说的新的 porductID。如果我们比较它,那么它总是相等的
2021-03-28 02:12:23
@BastianVoigt 它应该是 prevProps,因为在 props 改变后将调用 componentDidUpdate,这将与我们在 getDerivedStateFromProps 中设置的 nextProps 相同。
2021-03-31 02:12:23
ComponentWillReceiveProps 现在也被弃用并被认为是不安全的......还有其他方法可以做到吗?
2021-04-13 02:12:23

尽管上述所有方法都有效,但我认为没有必要使用getDerivedStateFromProps. 基于 React 文档,“如果您想仅在 prop 更改时重新计算某些数据,请改用 memoization helper”。

在这里,相反,我建议简单地使用componentDidUpdate并更改Componentto PureComponenet

参考 React 文档,PureComponenet只有在至少一个 state 或 prop 值发生变化时才重新渲染。更改是通过对 state 和 prop 键进行浅层比较来确定的。

  componentDidUpdate = (prevProps) => {
    if(this.props.match.params.id !== prevProps.match.params.id ) {
      // fetch the new product based and set it to the state of the component
   };
  };

请注意,以上仅当您将 Component 更改为 PureComponent 时才有效,并且显然您需要从 React 导入它。

就我而言,它也适用于常规组件。
2021-03-24 02:12:23

如果您不在组件中维护状态,componentDidUpdate则无需使用getDerivedStateFromProps

  componentDidUpdate(prevProps) {
    const { match: { params: { value } } } = this.props
    if (prevProps.match.params.value !== value){
      doSomething(this.props.match.params.value)
    }
  }