简体   繁体   English

反应:从渲染方法外部更新组件的道具而不使用状态

[英]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组件ProductProductInfoPanel 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.

相关问题 一种从外部调用 React 组件方法的方法(使用 state 和 props) - A way to call React component's method from outside (with it's state and props) 有没有办法在不使用道具的情况下更新反应组件? - Is there a way to update react component without using props? 如何在React中的render方法之外的函数中渲染组件? - How to render component from a function outside the render method in React? 如何更新使用ReactDOM.render()呈现的React组件的道具 - How to update props of React Component rendered using ReactDOM.render() 从组件外部访问React组件的方法/状态 - Access a React component method / state from outside the component React-无法通过prop设置组件的状态 - React - can't set component's state from props 如何基于道具更新React组件状态 - How to update react component state based on props 尝试使用类组件中的方法更新状态中的道具 - Trying to update props in state with method in class component 如何将 function 从 FUNCTIONAL 传递给 CLASS 组件并在渲染外部访问它(没有 prop ),在反应 js 中使用上下文? - How to pass function from FUNCTIONAL to CLASS component and access it outside of render( without prop ), using context in react js? 从外部触发时无法更新 React 组件 state - Can't update React Component state when triggered from outside
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM