簡體   English   中英

反應:從渲染方法外部更新組件的道具而不使用狀態

[英]React: update component's props from outside of render method without using state

這是我想要達到的目標。 我在ProductList組件內部顯示了兩個React組件ProductProductInfoPanel Product顯示有關Product選定信息,例如產品名稱和價格。 單擊產品后,將在ProductInfoPanel顯示更多詳細信息。 因此,我需要將wah twas單擊傳遞給ProductInfoPanel

這是我目前將它們連接在一起的方式。 每個Product都會獲得一個傳入的單擊處理程序,該調用處理程序將在調用時返回product對象,然后將其傳遞到ProductInfoPanel的props中。 ProductList使用狀態來跟蹤單擊的內容,因此當其更改時,它將觸發信息面板的重新呈現。

class ProductList extends React.Component {
  render() {
    return (
      <div>

        <div className='content'>

          <ul>
            { this.props.products.map((product, index) => {
              return (
                <li key={index}>
                  <Product product={product}
                    clickHandler={this.onProductClicked.bind(this)}/>
                </li>
              );
            })}
          </ul>

        </div>

        <div className='side-panel'>
          <ProductInfoPanel product={this.state.selectedProduct} />
        </div>

      </div>
    );
  }

  onProductClicked(clickedProduct) {
      // Use the product object that was clicked, and updates the state.
      // This updates the info panel content.
      this.setState({ selectedProduct: clickedProduct });
  }

}

這大致是兩個組件的構造方式。

class Product extends React.Component {
  render() {
   // Even though it needs only name and price, it gets the whole product
   // object passed in so that it can pass it to the info panel in the
   // click handler.
    return (
      <div onClick={this.onClicked.bind(this)}>
        <span>{this.props.product.name}</span>
        <span>{this.props.product.price}</span>
      </div>
    );
  }

  onClicked(e) {
    this.props.clickHandler(this.props.product);
  }
}

class ProductInfoPanel extends React.Component {
  render() {
    // Info panel displays more information about a product.
    return (
      <ul>
        <li>{this.props.product.name}</li>
        <li>{this.props.product.price}</li>
        <li>{this.props.product.description}</li>
        <li>{this.props.product.rating}</li>
        <li>{this.props.product.review}</li>
      </ul>
    );
  }
}

這是我能想到的最好的方法,但是使用狀態來跟蹤單擊了什么產品仍然對我來說是錯誤的。 我的意思是,這實際上不是組件的狀態,對嗎?

如果我可以從render方法外部更新引用的React組件的props ,那么我將嘗試將對ProductInfoPanel的引用傳遞給每個Product ,以便他們可以在其點擊處理程序中進行更新。

有沒有一種方法可以實現我想要的並且避免使用狀態來跟蹤單擊的內容?

您可以使用類似redux之類的類似助熔劑的庫,或使用諸如mobx之類的替代來從組件中刪除狀態管理,但是我個人的感覺是使它盡可能地簡單,直到您真正感覺到添加另一層會有很大的好處為止。抽象到您的項目中。

我曾經在默認情況下使用redux來啟動項目,但后來我踢了一下自己,因為事實證明,引入redux實現的額外復雜性實際上對於一個相當小而簡單的項目來說是過大的。 我不知道是否有硬性規定不知道何時應該回避使用標准狀態,而引入另一個庫來為您管理它,但是我了解到,最先最簡單,最簡單的方法是這樣做最安全您確實認為引入另一個依賴關系確實有實際好處。


有關當前代碼的一些建議...

您正在將屬性綁定到屬性中,如下所示:

<Product product={product} clickHandler={this.onProductClicked.bind(this)}/>

當您調用函數bind它實際上會返回一個新的函數實例,因此React的協調器會將其視為進入組件的新道具,因此將始終重新渲染子組件樹。 有一點要注意。 作為一種替代方法,您可以像這樣在構造器中進行早期綁定:

class ProductList extends React.Component {
  constructor(props) {
    super(props);
    this.onProductClicked = this.onProductClicked.bind(this);
  }
  render() {
    ...
        <li key={index}>
          <Product product={product}
            clickHandler={this.onProductClicked}/>
        </li>
    ...
  }
}

另外,在上面提供index (它們是唯一的key道具)-您應該考慮使用product模型中的唯一標識符(如果有)。 這樣,如果您從列表中添加或刪除項目,React將有更多信息來知道是否應重新渲染所有Product組件實例。

例如:

render() {
  ...
    { 
      this.props.products.map((product) => 
        <li key={product.id}>
          <Product product={product}
            clickHandler={this.onProductClicked}/>
        </li>
      )
    }

  ...
}

在此處閱讀有關這些概念的更多信息: https : //facebook.github.io/react/docs/advanced-performance.html

我覺得很好 如果有更多組件對SelectedProduct更改做出響應,那么讓父組件控制狀態的價值將更加明顯。 在您的情況下,似乎沒有必要,因為僅更改了一個組件。

但是,如果您的Product也通過突出顯示SelectedProduct了響應,而RecentlyViewedProducts列表以某種方式對SelectedProduct進行了響應,那么很明顯, SelectedProduct不是ProductInfoPanel的狀態,而是該狀態的更高級部分。它是觀察者的應用程序。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM