我正在编写此产品列表组件,而我正在与各州进行斗争。列表中的每个产品本身就是一个组件。一切都按照假设呈现,除了在支柱改变时组件没有更新。我正在使用重构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
。
另一个澄清:currentProducts
和setProducts
分别是保存购物车数据的类(模型)中的属性和方法。这也很有效,不会抛出异常或显示意外行为。
此处的预期行为是:在将产品添加到购物车时,在更新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
。我想这会奏效。但在移动之前,我想知道我在这里做错了什么。
答案 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)
这里的变化是:
withPropsOnChange
,用于处理addedToCart
&#34;计算&#34;; withState
以声明并为addedToCart
; setAddedToCart(true)
处理程序中的addToCart
; componentWillReceiveProps
添加lifecycle
事件,以便在道具更改时更新addedToCart
。其中一些更新基于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)
。更明确了。