[英]How to get React/recompose component updated when props are changed?
I'm writing this product list component and I'm struggling with states.我正在编写这个产品列表组件,但我正在为状态而苦苦挣扎。 Each product in the list is a component itself.列表中的每个产品本身都是一个组件。 Everything is rendering as supposed, except the component is not updated when a prop changes.一切都按预期渲染,除了在 prop 更改时组件不会更新。 I'm using recompose's withPropsOnChange()
hoping it to be triggered every time the props in shouldMapOrKeys
is changed.我正在使用 recompose 的withPropsOnChange()
希望每次更改shouldMapOrKeys
的道具时shouldMapOrKeys
触发它。 However, that never happens.然而,这永远不会发生。
Let me show some code:让我展示一些代码:
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)
I don't think it's relevant but addToCart
function returns a Promise.我认为这addToCart
但addToCart
函数返回一个 Promise。 Right now, it always resolves to true
.现在,它总是解析为true
。
Another clarification: currentProducts
and setProducts
are respectively an attribute and a method from a class (model) that holds cart data.另一个说明: currentProducts
和setProducts
分别是一个属性和一个方法,来自一个保存购物车数据的类(模型)。 This is also working good, not throwing exceptions or showing unexpected behaviors.这也很好用,不会抛出异常或显示意外行为。
The intended behavior here is: on adding a product to cart and after updating the currentProducts
list, the addedToCart
prop would change its value.这里的预期行为是:将产品添加到购物车并更新currentProducts
列表后, addedToCart
道具将更改其值。 I can confirm that currentProducts
is being updated as expected.我可以确认currentProducts
正在按预期更新。 However, this is part of the code is not reached (I've added a breakpoint to that line):但是,这是未到达代码的一部分(我在该行中添加了一个断点):
return Object.assign({
addedToCart: currentProducts.indexOf(product.id) !== -1,
}, props)
Since I've already used a similar structure for another component -- the main difference there is that one of the props I'm "listening" to is defined by withState()
--, I'm wondering what I'm missing here.由于我已经为另一个组件使用了类似的结构——主要区别在于我“听”的一个道具是由withState()
定义的——我想知道我在这里遗漏了什么. My first thought was the problem have been caused by the direct update of currentProducts
, here:我的第一个想法是问题是由currentProducts
的直接更新引起的,这里:
currentProducts.push(product.id)
So I tried a different approach:所以我尝试了一种不同的方法:
const products = [ product.id ].concat(currentProducts)
setProducts(products)
That didn't change anything during execution, though.不过,这在执行过程中没有任何改变。
I'm considering using withState
instead of withPropsOnChange
.我正在考虑使用withState
而不是withPropsOnChange
。 I guess that would work.我想那会奏效。 But before moving that way, I wanted to know what I'm doing wrong here.但在采取这种方式之前,我想知道我在这里做错了什么。
As I imagined, using withState
helped me achieving the expected behavior.正如我想象的那样,使用withState
帮助我实现了预期的行为。 This is definitely not the answer I wanted, though.不过,这绝对不是我想要的答案。 I'm anyway posting it here willing to help others facing a similar issue.无论如何,我在这里发布它愿意帮助面临类似问题的其他人。 I still hope to find an answer explaining why my first code didn't work in spite of it was throwing no errors.我仍然希望找到一个答案来解释为什么我的第一个代码尽管没有抛出任何错误但仍然不起作用。
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)
The changes here are:这里的变化是:
withPropsOnChange
, which used to handle the addedToCart
"calculation";除去withPropsOnChange
,其用来处理addedToCart
“计算”;withState
to declare and create a setter for addedToCart
;添加withState
来为addedToCart
声明和创建一个 setter ;setAddedToCart(true)
inside the addToCart
handler when the product is successfully added to cart;当产品成功添加到购物setAddedToCart(true)
开始调用addToCart
处理程序中的setAddedToCart(true)
;componentWillReceiveProps
event through the recompose's lifecycle
to update the addedToCart
when the props change.通过 recompose 的lifecycle
添加componentWillReceiveProps
事件以在道具更改时更新addedToCart
。Some of these updates were based on this answer .其中一些更新基于此答案。
I think the problem you are facing is due to the return value for withPropsOnChange
.我认为您面临的问题是由于withPropsOnChange
的返回值。 You just need to do:你只需要做:
withPropsOnChange([
'product',
'currentProducts',
], ({
product,
currentProducts,
}) => ({
addedToCart: currentProducts.indexOf(product.id) !== -1,
})
)
As it happens with withProps
, withPropsOnChange
will automatically merge your returned object into props.与withProps
, withPropsOnChange
会自动将返回的对象合并到 props 中。 No need of Object.assign()
.不需要Object.assign()
。
Reference: https://github.com/acdlite/recompose/blob/master/docs/API.md#withpropsonchange参考: https : //github.com/acdlite/recompose/blob/master/docs/API.md#withpropsonchange
ps: I would also replace the condition to be currentProducts.includes(product.id)
if you can. ps:如果可以的话,我也会将条件替换为currentProducts.includes(product.id)
。 It's more explicit.它更明确。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.