Как обновить компонент React / Recompose при смене реквизита? - PullRequest
0 голосов
/ 18 мая 2018

Я пишу этот компонент списка продуктов и борюсь с государствами.Каждый продукт в списке является самим компонентом.Все отображается так, как предполагалось, за исключением того, что компонент не обновляется при смене реквизита.Я использую рекомпозицию 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.Я думаю, это будет работать.Но прежде чем идти по этому пути, я хотел знать, что я здесь делаю неправильно.

1 Ответ

0 голосов
/ 18 мая 2018

Как я себе представлял, использование 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;
  3. Начал вызывать setAddedToCart(true)внутри обработчика addToCart при успешном добавлении товара в корзину;
  4. Добавлено событие componentWillReceiveProps через lifecycle перекомпоновки для обновления addedToCart при изменении реквизита.

Некоторые из этих обновлений были основаны на этом ответе .

...