web-dev-qa-db-de.com

React lädt keine Komponentendaten neu, wenn Routenparameter oder Abfragen geändert werden

Ich habe eine "Home" -Komponente mit Links, und wenn Sie auf einen Link klicken, wird die Produktkomponente mit dem Produkt geladen. Ich habe auch eine andere Komponente, die immer sichtbar ist und Links zu den "zuletzt besuchten Produkten" anzeigt.

Diese Links funktionieren auf einer Produktseite nicht. Die URL wird aktualisiert, wenn ich auf den Link klicke und ein Rendering stattfindet, aber die Produktkomponente wird nicht mit dem neuen Produkt aktualisiert.

Siehe dieses Beispiel: Codesandbox-Beispiel

Hier sind die Routen in 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>;

Die Links in ProductHistory sehen folgendermaßen aus:

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

Also passen sie zum Route path="/products/:product".

Wenn ich mich auf einer Produktseite befinde und versuche, einem ProductHistory-Link zu folgen, wird die URL aktualisiert und gerendert, die Komponentendaten werden jedoch nicht geändert. Im Beispiel Codesandbox können Sie die Warnung in der Renderfunktion für Produktkomponenten auskommentieren, um zu sehen, dass sie angezeigt wird, wenn Sie dem Link folgen, aber nichts passiert.

Ich weiß nicht, was das Problem ist ... Können Sie das Problem erklären und eine Lösung finden? Das wäre toll!

19
Galivan

Zusammen mit componentDidMount müssen Sie auch componentWillReceiveProps implementieren oder getDerivedStateFromProps (ab v16.3.0) auf der Seite Products verwenden, da dieselbe Komponente re-rendered Mit aktualisiertem params und not re-mounted, Wenn Sie die Routenparameter ändern, da Parameter als Requisiten an die Komponente übergeben werden und sich bei Requisiten ändern, React Komponenten werden neu gerendert und nicht neu gemountet.

BEARBEITEN: ab Version 16.3.0 verwenden Sie getDerivedStateFromProps , um den Status basierend auf Requisiten festzulegen/zu aktualisieren (dies ist nicht erforderlich) spezifiziere es in zwei verschiedenen Lifecyle Methoden)

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

Vor Version 16.3.0 würden Sie componentWillReceiveProps verwenden

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

      })
    }
  }

Arbeitscodesandbox

28
Shubham Khatri

Da die Produktkomponente bereits geladen ist, wird sie nicht erneut geladen. Sie müssen die neue Produkt-ID in der folgenden Methode der Komponente behandeln

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

Mit der neuesten Version von react (ab 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
  }
}
6
Prakash S

Obwohl alle oben genannten Möglichkeiten funktionieren, sehe ich keinen Grund, getDerivedStateFromProps zu verwenden. Basierend auf React docs, "Wenn Sie einige Daten nur dann neu berechnen möchten, wenn sich eine Requisite ändert, verwenden Sie stattdessen einen Notizen-Helfer".

Hier würde ich stattdessen vorschlagen, einfach componentDidUpdate zu verwenden und Component in PureComponenet zu ändern.

Mit Bezug auf React docs, PureComponenets wird nur dann neu gerendert, wenn sich mindestens ein Status- oder Requisitenwert ändert. Die Änderung wird durch einen flachen Vergleich von Status- und Requisitenschlüsseln ermittelt.

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

Bitte beachten Sie, dass die oben genannten Schritte nur funktionieren, wenn Sie die Komponente in PureComponent ändern und sie offensichtlich aus React importieren müssen.

0
Amir Salar

Wenn Sie den Status in Ihrer Komponente nicht beibehalten, können Sie componentDidUpdate verwenden, ohne getDerivedStateFromProps zu benötigen:

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