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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/48139281/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 04:01:51  来源:igfitidea点击:

React doesn't reload component data on route param change or query change

javascriptreactjsreact-routerreact-router-v4react-router-dom

提问by Galivan

I have a "home" component with links, and when you click a link the product component is loaded with the product. I also have another component which is always visible, showing links to the "recently visited products".

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

These links don't work when on a product page. The url updates when I click the link, and a render occurs, but the product component doesn't update with the new product.

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

See this example: Codesandbox example

请参阅此示例: Codesandbox 示例

Here are the routes in index.js:

以下是 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>;

The links in ProductHistory look like this:

ProductHistory 中的链接如下所示:

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

So they match the Route path="/products/:product".

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

When I am on a product page and try to follow a ProductHistory link, the URL updates and a render occurs, but the component data doesn't change. In the Codesandbox example you can uncomment the alert in Product components render function to see that it renders when you follow the link, but nothing happens.

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

I don't know what the problem is...Can you explain the problem and find a solution? That would be great!

我不知道是什么问题...你能解释一下问题并找到解决方案吗?那很好啊!

回答by Shubham Khatri

Along with componentDidMount, You also need to implement the componentWillReceivePropsor use getDerivedStateFromProps(from v16.3.0 onwards) in Productspage since the same component is re-renderedwith updated paramsand not re-mountedwhen you change the route params, this is because params are passed as props to the component and on props change, React components re-render and not re-mounted.

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

EDIT:from v16.3.0 use getDerivedStateFromPropsto set/update state based on props(no need to specify it in two different lifecyle methods)

编辑:从 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;
}

Prior v16.3.0, you would use componentWillReceiveProps

在 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

      })
    }
  }

Working codesandbox

工作代码沙盒

回答by Prakash S

As Product component is already loaded it will not reload. You have to handle new product id in the below method of component

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

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

With latest version of react(16.3.0 onwards)

使用最新版本的 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
  }
}

回答by Amir Salar

Although all the above-mentioned ways will work, I don't see a point to use getDerivedStateFromProps. Based on React docs, "if you want to re-compute some data only when a prop changes, use a memoization helper instead".

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

Here, instead, I would suggest simply using componentDidUpdatealong with changing the Componentto PureComponenet.

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

With reference to React docs, PureComponenets only rerender if at least one state or prop value changes. Change is determined by doing a shallow comparison of state and prop keys.

参考 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
   };
  };

Please note that the above only work if you change the Component to PureComponent, and obviously, you need to import it from React.

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

回答by CLL

If you aren't maintaining state in your component, you can use componentDidUpdatewithout the need for getDerivedStateFromProps:

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

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