繁体   English   中英

更改 props 时如何更新 React/recompose 组件?

[英]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)

我认为这addToCartaddToCart函数返回一个 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 我想那会奏效。 但在采取这种方式之前,我想知道我在这里做错了什么。

正如我想象的那样,使用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 “计算”;
  2. 添加withState来为addedToCart声明和创建一个 setter ;
  3. 当产品成功添加到购物setAddedToCart(true)开始调用addToCart处理程序中的setAddedToCart(true)
  4. 通过 recompose 的lifecycle添加componentWillReceiveProps事件以在道具更改时更新addedToCart

其中一些更新基于此答案

我认为您面临的问题是由于withPropsOnChange的返回值。 你只需要做:

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

withPropswithPropsOnChange会自动将返回的对象合并到 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.

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