![](/img/trans.png)
[英]How to update React props when web component attributes are updated async?
[英]How to get React/recompose component updated when props are changed?
我正在编写这个产品列表组件,但我正在为状态而苦苦挣扎。 列表中的每个产品本身都是一个组件。 一切都按预期渲染,除了在 prop 更改时组件不会更新。 我正在使用 recompose 的withPropsOnChange()
希望每次更改shouldMapOrKeys
的道具时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
但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
。 我想那会奏效。 但在采取这种方式之前,我想知道我在这里做错了什么。
正如我想象的那样,使用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
“计算”;withState
来为addedToCart
声明和创建一个 setter ;setAddedToCart(true)
开始调用addToCart
处理程序中的setAddedToCart(true)
;lifecycle
添加componentWillReceiveProps
事件以在道具更改时更新addedToCart
。其中一些更新基于此答案。
我认为您面临的问题是由于withPropsOnChange
的返回值。 你只需要做:
withPropsOnChange([
'product',
'currentProducts',
], ({
product,
currentProducts,
}) => ({
addedToCart: currentProducts.indexOf(product.id) !== -1,
})
)
与withProps
, withPropsOnChange
会自动将返回的对象合并到 props 中。 不需要Object.assign()
。
参考: https : //github.com/acdlite/recompose/blob/master/docs/API.md#withpropsonchange
ps:如果可以的话,我也会将条件替换为currentProducts.includes(product.id)
。 它更明确。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.