如何在更改道具时更新React / recompose组件?

时间:2018-05-18 11:05:15

标签: reactjs recompose

我正在编写此产品列表组件,而我正在与各州进行斗争。列表中的每个产品本身就是一个组件。一切都按照假设呈现,除了在支柱改变时组件没有更新。我正在使用重构withPropsOnChange()希望每次shouldMapOrKeys中的道具发生变化时触发它。但是,这种情况从未发生过。

让我展示一些代码:

import React from 'react'
import classNames from 'classnames'
import { compose, withPropsOnChange, withHandlers } from 'recompose'
import { addToCart } from 'utils/cart'

const Product = (props) => {

  const {
    product,
    currentProducts,
    setProducts,
    addedToCart,
    addToCart,
  } = props

  const classes = classNames({
    addedToCart: addedToCart,
  })

  return (
    <div className={ classes }>
      { product.name }
      <span>$ { product.price }/yr</span>
      { addedToCart ?
        <strong>Added to cart</strong> :
        <a onClick={ addToCart }>Add to cart</a> }
    </div>
  )
}

export default compose(
  withPropsOnChange([
    'product',
    'currentProducts',
  ], (props) => {

    const {
      product,
      currentProducts,
    } = props

    return Object.assign({
      addedToCart: currentProducts.indexOf(product.id) !== -1,
    }, props)
  }),
  withHandlers({
    addToCart: ({
      product,
      setProducts,
      currentProducts,
      addedToCart,
    }) => {
      return () => {
        if (addedToCart) {
          return
        }
        addToCart(product.id).then((success) => {
          if (success) {
            currentProducts.push(product.id)
            setProducts(currentProducts)
          }
        })
      }
    },
  }),
)(Product)

我不认为它是相关的,但addToCart函数返回一个Promise。现在,它总是解析为true

另一个澄清:currentProductssetProducts分别是保存购物车数据的类(模型)中的属性和方法。这也很有效,不会抛出异常或显示意外行为。

此处的预期行为是:在将产品添加到购物车时,在更新currentProducts列表后,addedToCart道具会更改其值。我可以确认currentProducts正在按预期更新。但是,这是未达到代码的一部分(我在该行添加了一个断点):

return Object.assign({
  addedToCart: currentProducts.indexOf(product.id) !== -1,
}, props)

因为我已经为另一个组件使用了类似的结构 - 主要区别在于我正在“监听”的一个道具是由withState()定义的 - 我想知道是什么我在这里失踪了。我的第一个想法是问题是由currentProducts的直接更新引起的,这里:

currentProducts.push(product.id)

所以我尝试了另一种方法:

const products = [ product.id ].concat(currentProducts)
setProducts(products)

但是在执行期间并没有改变任何事情。

我正在考虑使用withState代替withPropsOnChange。我想这会奏效。但在移动之前,我想知道我在这里做错了什么。

2 个答案:

答案 0 :(得分:0)

正如我想象的那样,使用withState帮助我实现了预期的行为。但这绝对不是我想要的答案。无论如何,我在这里张贴它愿意帮助其他人面对类似的问题。我仍然希望找到一个答案,解释为什么我的第一个代码尽管没有错误但仍无法正常工作。

export default compose(
  withState('addedToCart', 'setAddedToCart', false),
  withHandlers({
    addToCart: ({
      product,
      setProducts,
      currentProducts,
      addedToCart,
    }) => {
      return () => {
        if (addedToCart) {
          return
        }
        addToCart(product.id).then((success) => {
          if (success) {
            currentProducts.push(product.id)
            setProducts(currentProducts)
            setAddedToCart(true)
          }
        })
      }
    },
  }),
  lifecycle({
    componentWillReceiveProps(nextProps) {
      if (this.props.currentProducts !== nextProps.currentProducts ||
          this.props.product !== nextProps.product) {
        nextProps.setAddedToCart(nextProps.currentProducts.indexOf(nextProps.product.id) !== -1)
      }
    }
  }),
)(Product)

这里的变化是:

  1. 移除withPropsOnChange,用于处理addedToCart&#34;计算&#34;;
  2. 添加withState以声明并为addedToCart;
  3. 创建一个setter
  4. 当产品成功添加到购物车时,开始致电setAddedToCart(true)处理程序中的addToCart;
  5. 通过重组componentWillReceiveProps添加lifecycle事件,以便在道具更改时更新addedToCart
  6. 其中一些更新基于this answer

答案 1 :(得分:0)

我认为您面临的问题归因于withPropsOnChange的返回值。您只需要这样做:

withPropsOnChange([
    'product',
    'currentProducts',
  ], ({
      product,
      currentProducts,
    }) => ({
      addedToCart: currentProducts.indexOf(product.id) !== -1,
    })
)

withProps中,withPropsOnChange会自动将您返回的对象合并为道具。不需要Object.assign()

参考:https://github.com/acdlite/recompose/blob/master/docs/API.md#withpropsonchange

p.s .:如果可以的话,我也将条件替换为currentProducts.includes(product.id)。更明确了。