简体   繁体   中英

Is passing an event from a presentational to container component an anti-pattern when using Redux?

I'm very new to Redux and I'm trying to build an old React app again using it, to learn. I'm running into a bit of a hurdle with where to put the logic.

I'm under the impression that keeping actions and reducers as simple as possible logic-wise is the way to go, but that leaves me with having some logic inside the components themselves. To me it makes sense to utilize presentational and container components in this setup, but I also want to make sure I am fully grasping the way data is passed using Redux.

For example I have:

ProductContainer
  Product

I have a ProductContainer component which checks whether the component is 'selected' or not, and the Product which is just presentational markup to show description and a button to 'select'.

I also have a selected_products object in my store that has all of the products that are currently selected.

Obviously the user clicks the Product component, but would I add the logic to either add or remove it to the store of selected products in an action straight from that component? or would i trigger a function in the ProductContainer parent to check selected_products then trigger either an 'add' action or 'remove' action?

Thanks!

The way I would approach this is to have logic functions for handling adding and removing in the ProductContainer where actions are dispatched. These functions are then passed to the Product component as a prop so they can be called in a button or whatever.

for example:

// ProductContainer.js 
import React from 'react'
import Product from './Product'

export class ProductContainer extends React.Component { 
  constructor(props) {
    super(props)
    this.handleRemoveProduct = this.handleRemoveProduct.bind(this)
    this.handleAddProduct = this.handleAddProduct.bind(this)
  }

  handleRemoveProduct(productId) {
    // do your remove here
  }

  handleAddProduct(productDetails){
    // do your adding here
  }

  render() {
    return (
      <Product handleAddProduct={this.handleAddProduct} handleRemoveProduct={this.handleRemoveProduct} />
    )
  }
}

export default ProductContainer

then

// Product.js
import React from 'react'

export const Product = (props) => {
  const {handleAddProduct, handleRemoveProduct} = props
  render () {
    return (
      <div>
        <Button onClick={handleAddProduct(someData)}
        <Button onClick={handleRemoveProduct(productId)}
      </div>
    )
  }
}

export default Product

Hope this helps.

Don't over-think the whole "presentational" and "container" concepts. They're useful mental models, but not any kind of absolute pattern that you must follow. I have some links to several articles discussing those patterns as part of my React/Redux links list, under React Component Patterns .

I tend towards putting the majority of the logic outside the components, in action creators. I recently wrote a blog post on that topic: Idiomatic Redux: Why Use Action Creators? .

There's also nothing that says that "reducers have to be as simple as possible". Sometimes they may be simple, sometimes they may be complex. Totally depends on your own app and your own preferences. See these sections in the Redux docs for more info: FAQ: Where should I put my "business logic"? and Structuring Reducers .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM