React не перезагружает данные компонента при изменении параметров маршрута или изменении запроса

у меня есть компонент "home" со ссылками, и когда вы нажимаете ссылку, компонент продукта загружается с продуктом. У меня также есть еще один компонент, который всегда виден, показывая ссылки на"недавно посещенные продукты".

эти ссылки не работают, когда на странице продукта. Url-адрес обновляется, когда я нажимаю ссылку, и происходит рендеринг, но компонент продукта не обновляется с новым продуктом.

посмотреть этот пример: Codesandbox пример

вот маршруты в индексе.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 можно раскомментировать оповещение в функции визуализации компонентов продукта, чтобы увидеть, что оно отображается при переходе по ссылке, но ничего не происходит.

Я не знаю, в чем проблема...Можете ли вы объяснить проблему и найти решение? Это было бы здорово!

2 ответов


вместе с componentDidMount, вам также необходимо реализовать на Products страница, так как тот же компонент re-rendered с обновленными params и not re-mounted при изменении параметров маршрута это происходит потому, что параметры передаются в качестве реквизита компоненту, а при изменении реквизита компоненты React повторно визуализируются и не монтируются.

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

      })
    }
  }

рабочие codesandbox

С последней версией React(v16.3.0 вперед) вы можете использовать getDerivedStateFromProps для установки / обновления состояния на основе реквизита (нет необходимости указывать его в двух разных методах lifecyle)

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

поскольку компонент продукта уже загружен, он не перезагрузится. Вы должны обрабатывать новый идентификатор продукта в приведенном ниже методе component

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
  }
}