繁体   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