web-dev-qa-db-fra.com

React ne recharge pas les données de composant lors du changement de paramètre de route ou de requête

J'ai un composant "home" avec des liens, et lorsque vous cliquez sur un lien, le composant est chargé avec le produit. J'ai aussi un autre composant qui est toujours visible, montrant des liens vers les "produits récemment visités".

Ces liens ne fonctionnent pas sur une page de produit. L'URL se met à jour lorsque je clique sur le lien et un rendu se produit, mais le composant du produit ne met pas à jour le nouveau produit.

Voir cet exemple: exemple de Codesandbox

Voici les itinéraires dans 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>;

Les liens dans ProductHistory ressemblent à ceci:

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

Donc, ils correspondent à la Route path="/products/:product".

Lorsque je suis sur une page de produit et que je tente de suivre un lien ProductHistory, l'URL se met à jour et un rendu se produit, mais les données du composant ne changent pas. Dans l'exemple Codesandbox, vous pouvez supprimer le commentaire de l'alerte dans la fonction de rendu des composants du produit pour voir qu'elle s'affiche lorsque vous suivez le lien, mais rien ne se produit.

Je ne sais pas quel est le problème ... Pouvez-vous expliquer le problème et trouver une solution? Ce serait génial!

19
Galivan

Avec componentDidMount, vous devez également implémenter le componentWillReceiveProps ou utiliser getDerivedStateFromProps (à partir de la version 16.3.0) dans la page Products car le même composant est re-rendered avec les mises à jour params et not re-mounted lorsque vous modifiez les paramètres de route, cela est dû au fait que les paramètres sont transmis en tant qu’éléments au composant et que, lorsqu’ils changent d’accessoires, React les composants sont restitués et non montés à nouveau.

EDIT: à partir de v16.3.0, utilisez getDerivedStateFromProps pour définir/mettre à jour l'état en fonction des accessoires (inutile de spécifiez-le dans deux méthodes de cycle de vie différentes)

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

Avant la version 16.3.0, vous utiliseriez le composantWillReceiveProps

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 de travail

28
Shubham Khatri

Comme le composant Produit est déjà chargé, il ne sera pas rechargé. Vous devez gérer un nouvel identifiant de produit dans la méthode de composant ci-dessous

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

Avec la dernière version de react (à partir de 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

Bien que toutes les méthodes mentionnées ci-dessus fonctionnent, je ne vois pas pourquoi utiliser getDerivedStateFromProps. Basé sur React docs, "si vous voulez recalculer certaines données uniquement lorsqu'un accessoire change, utilisez plutôt un assistant de mémorisation".

Ici, au lieu de cela, je suggérerais simplement d’utiliser componentDidUpdate en changeant le Component en PureComponenet.

En faisant référence à React docs, PureComponenets uniquement restituer si au moins une valeur d'état ou prop change. Le changement est déterminé en effectuant une comparaison superficielle des clés d'état et 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
   };
  };

Veuillez noter que ce qui précède ne fonctionne que si vous modifiez le composant en PureComponent et, évidemment, vous devez l'importer à partir de React.

0
Amir Salar

Si vous ne maintenez pas l'état de votre composant, vous pouvez utiliser componentDidUpdate sans avoir besoin de getDerivedStateFromProps:

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