[英]React: update component's props from outside of render method without using state
Here is what I'm trying to achieve. 这是我想要达到的目标。 I have two React components Product
and ProductInfoPanel
, shown inside a ProductList
component. 我在ProductList
组件内部显示了两个React组件Product
和ProductInfoPanel
。 Product
displays selected information about a product, such as product name, and price. Product
显示有关Product
选定信息,例如产品名称和价格。 When a product is clicked, more details will be shown in the ProductInfoPanel
. 单击产品后,将在ProductInfoPanel
显示更多详细信息。 So I need to pass wah twas clicked to the ProductInfoPanel
. 因此,我需要将wah twas单击传递给ProductInfoPanel
。
Here is how I currently wire them up together. 这是我目前将它们连接在一起的方式。 Each Product
gets a click handler passed in, which passes back the product
object when invoked, then that is passed into the ProductInfoPanel
's props. 每个Product
都会获得一个传入的单击处理程序,该调用处理程序将在调用时返回product
对象,然后将其传递到ProductInfoPanel
的props中。 The ProductList
uses state to keep track of what was clicked, so when it changes, it triggers the re-rendering of the info panel. 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 });
}
}
Here is roughly how the two components are constructed. 这大致是两个组件的构造方式。
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>
);
}
}
This is the best I could come up with, but using state to keep track of what product was clicked still sounds wrong to me. 这是我能想到的最好的方法,但是使用状态来跟踪单击了什么产品仍然对我来说是错误的。 I mean, it's not really a state of a component, is it? 我的意思是,这实际上不是组件的状态,对吗?
If I could update props
of a referenced React component from outside of the render
method, then I'd try to pass a reference to a ProductInfoPanel
to each Product
, so they could do update it in their click handler. 如果我可以从render
方法外部更新引用的React组件的props
,那么我将尝试将对ProductInfoPanel
的引用传递给每个Product
,以便他们可以在其点击处理程序中进行更新。
Is there a way to achieve what I want and avoid using state to keep track of what was clicked? 有没有一种方法可以实现我想要的并且避免使用状态来跟踪单击的内容?
You could use a flux-like library like redux , or an alternative like mobx to remove state management from your component, but my personal feeling is to keep it as simple as possible until you really feel like there will be significant benefit in adding another layer of abstraction into your project. 您可以使用类似redux之类的类似助熔剂的库,或使用诸如mobx之类的替代品来从组件中删除状态管理,但是我个人的感觉是使它尽可能地简单,直到您真正感觉到添加另一层会有很大的好处为止。抽象到您的项目中。
I used to start off projects using redux by default but then one time I kicked myself as it turned out that the added complexity of introducing a redux implementation turned out to be overkill for what was actually a fairly small and simple project. 我曾经在默认情况下使用redux来启动项目,但后来我踢了一下自己,因为事实证明,引入redux实现的额外复杂性实际上对于一个相当小而简单的项目来说是过大的。 I don't know if there is a hard line to know when you should shy away from using standard state and introduce another library to manage it for you, but I have learned that it's probably safest to do it the easiest and simplest way first until you genuinely feel there is actual benefit in bring in another dependency. 我不知道是否有硬性规定不知道何时应该回避使用标准状态,而引入另一个库来为您管理它,但是我了解到,最先最简单,最简单的方法是这样做最安全您确实认为引入另一个依赖关系确实有实际好处。
A few bits of advice on your current code... 有关当前代码的一些建议...
You are binding your functions in the properties like so: 您正在将属性绑定到属性中,如下所示:
<Product product={product} clickHandler={this.onProductClicked.bind(this)}/>
When you call function bind
it actually returns a new function instance, therefore React's reconciler will see it as a new prop coming into your component and will therefore always re-render the subcomponent tree. 当您调用函数bind
它实际上会返回一个新的函数实例,因此React的协调器会将其视为进入组件的新道具,因此将始终重新渲染子组件树。 Something to be aware of. 有一点要注意。 As an alternative approach you can do early binding in your constructor like so: 作为一种替代方法,您可以像这样在构造器中进行早期绑定:
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>
...
}
}
Additionally, where you are providing index
as they unique key
prop above - you should consider using a unique identifier from your product
model (if it's available). 另外,在上面提供index
(它们是唯一的key
道具)-您应该考虑使用product
模型中的唯一标识符(如果有)。 That way if you add or remove items from the list React will have more information to know whether or not it should re-render all of the Product
component instances. 这样,如果您从列表中添加或删除项目,React将有更多信息来知道是否应重新渲染所有Product
组件实例。
For example: 例如:
render() {
...
{
this.props.products.map((product) =>
<li key={product.id}>
<Product product={product}
clickHandler={this.onProductClicked}/>
</li>
)
}
...
}
Read more about these concepts here: https://facebook.github.io/react/docs/advanced-performance.html 在此处阅读有关这些概念的更多信息: https : //facebook.github.io/react/docs/advanced-performance.html
I think it's fine. 我觉得很好 If there were more components that responded to changes in SelectedProduct
, then the value of having the parent component control the state would be more apparent. 如果有更多组件对SelectedProduct
更改做出响应,那么让父组件控制状态的价值将更加明显。 In your case, it might not seem necessary, since only a single component changes. 在您的情况下,似乎没有必要,因为仅更改了一个组件。
However, if your Product
also responded by highlighting the SelectedProduct
, and a RecentlyViewedProducts
list responded in some way to the SelectedProduct
, then it would become evident that the SelectedProduct
isn't the state of the ProductInfoPanel
, but state of a higher level part of the application that it's an observer of. 但是,如果您的Product
也通过突出显示SelectedProduct
了响应,而RecentlyViewedProducts
列表以某种方式对SelectedProduct
进行了响应,那么很明显, SelectedProduct
不是ProductInfoPanel
的状态,而是该状态的更高级部分。它是观察者的应用程序。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.