web-dev-qa-db-ja.com

Reactは、ルートパラメーターの変更またはクエリの変更時にコンポーネントデータをリロードしません

リンクのある「ホーム」コンポーネントがあり、リンクをクリックすると、製品コンポーネントに製品がロードされます。また、常に表示される別のコンポーネントもあり、「最近訪れた製品」へのリンクが表示されます。

これらのリンクは、製品ページでは機能しません。リンクをクリックするとURLが更新され、レンダリングが行われますが、製品コンポーネントは新しい製品で更新されません。

この例を参照してください: Codesandbox example

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の例では、製品コンポーネントのレンダリング機能のアラートのコメントを解除して、リンクをたどったときにレンダリングされることを確認できますが、何も起こりません。

問題が何なのかわかりません...問題を説明して解決策を見つけることができますか?それは素晴らしいことです!

19
Galivan

componentDidMountに加えて、componentWillReceivePropsを実装するか、getDerivedStateFromPropsページでProducts(v16.3.0以降)を使用する必要もあります。これは、同じコンポーネントがre-renderedであり、更新されたparamsnot re-mountedこれは、パラメーターが小道具としてコンポーネントに渡され、小道具が変更されると、Reactコンポーネントが再レンダリングされ、再マウントされないためです。

EDIT:v16.3.0から getDerivedStateFromProps を使用して、propsに基づいて状態を設定/更新します(2種類で指定する必要はありません)ライフサイクルメソッド)

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

      })
    }
  }

作業コードとボックス

28
Shubham Khatri

製品コンポーネントはすでにロードされているため、リロードされません。コンポーネントの以下のメソッドで新しい製品IDを処理する必要があります

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

反応の最新バージョン(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

上記の方法はすべて機能しますが、getDerivedStateFromPropsを使用するポイントは見当たりません。 Reactドキュメントに基づいて、「プロップが変更されたときにのみ一部のデータを再計算する場合は、代わりにメモ化ヘルパーを使用します」。

ここでは、代わりに、componentDidUpdateComponentに変更して、PureComponenetを使用することをお勧めします。

React docsを参照すると、PureComponenetsは、少なくとも1つの状態またはプロップ値が変更された場合にのみレンダリングします。変更は、状態キーとプロップキーの浅い比較を行うことで決定されます。

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

上記は、コンポーネントをPureComponentに変更した場合にのみ機能し、明らかに、Reactからインポートする必要があることに注意してください。

0
Amir Salar

コンポーネントの状態を維持していない場合は、componentDidUpdateを使用せずにgetDerivedStateFromPropsを使用できます。

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