I
I
Incold2020-06-12 12:59:18
React
Incold, 2020-06-12 12:59:18

Why doesn't the component update when React props change?

Hello! I ran into a problem, when the state of Redux changes, the parent component is updated and does not cause problems, but its children do not, although the props passed to them change.
Parent component:

function Basket(props) {
    return (
      <div className="d-flex flex-fill" id="basket">
        <div className="row container-fluid">
          <div className="col">
            <h4 className="display-4">Your order:</h4>
            <hr className="m-2"/>
            {
              this.props.order.map(item => {
                console.log(item); // Здесь всё хорошо, item (item.count) приходит новый
                // item - это объект, имеющий структуру {orderPizza: {...}, count: Number}
                // и ниже буде код action, который меняет item.count 
                return <OrderItem key={item.orderPizza._id} pizzaData={item} />
              })
            }
            <Link type="button" className="btn btn-warning my-3" to="/menu">Return to menu</Link>
          </div>
          <div className="col"></div>
        </div>
      </div>
    )
}

export default connect(
  state => ({
    order: state.basket.order,
    //count: state.basket.count,
    total: state.basket.total,
    currency: state.menu.currency
  }),
  null
)(Basket);


Child OrderItem (it is not updated):
function OrderItem(props) {
  const {orderPizza, count} = props.pizzaData;

  console.log(count); // тут при рендере, должно выводится количество, которое приходит из props, но при их изменении это не срабатывает, из чего я делаю вывод, что ререндер не произошёл

  return (
    <div className="row d-flex align-items-center orderItem my-2">
      <div className="col-3">
        <img src={images(`./${orderPizza.pizzaName}.jpg`)} alt="pizza"/>
      </div>
      <div className="col-3 text-center orderItemInfo">
        <div className="font-italic">{orderPizza.pizzaName}</div>
      </div>
      <div className="col-2">
        <div className="row p-0">
          <div className='col d-flex justify-content-center align-items-center pl-0'>
            <button className="btn btn-outline-success rounded-circle btn-sm"
              onClick={() => props.changeCount('plus', orderPizza._id)}
            >
              <i className="fa fa-plus"></i>
            </button>
          </div>
          <div className='col text-center orderItemInfo p-0'>
            <div>{count}</div>
          </div>
          <div className='col d-flex justify-content-center align-items-center pr-0'>
            <button className="btn btn-outline-danger rounded-circle btn-sm"
                    onClick={() => props.changeCount('minus', orderPizza._id)}
            >
              <i className="fa fa-minus"></i>
            </button>
          </div>
        </div>
      </div>
      <div className="col-3 text-center orderItemInfo">
        <div>{(orderPizza.price*props.currency.rate*count).toFixed(2)} <i className={`fa ${props.currency.symbol}`}></i></div>
      </div>
      <div className="col-1 text-center pl-0">
        <button className="btn"><i className="fa fa-close fa-2x"></i></button>
      </div>
    </div>
  )
}

export default connect(
  state => ({
    currency: state.menu.currency
  }),
  dispatch => ({
    changeCount(type, id) { // Этот action должен менять количество при нажатии на кнопку, он работает корректно, но происходит вышеописанная ситуация
      dispatch(changePizzaCount(type, id))
    }
  })
)(OrderItem);


action:
export const changePizzaCount = (type, id) => {
  return (dispatch, getState) => {
    const order = getState().basket.order;
    let index = order.findIndex(item => item.orderPizza._id === id);
    order[index].count =
      type === 'plus'
        ? order[index].count + 1
        : order[index].count - 1 < 1
          ? 1
          : order[index].count - 1;
    return dispatch({
      type: 'CHANGE_PIZZA_COUNT',
      order: order,
      pizzaPrice: type === 'plus' ? order[index].orderPizza.price : -order[index].orderPizza.price
    })
  }
}


reducer:
const initialState = {
  total: 0,
  count: 0, // этот count, отвечает за количество позиций в корзине, не обращайте на него внимания
  order: []
};

export default function basket(state=initialState, action) {

  switch (action.type) {
    ...
    case 'CHANGE_PIZZA_COUNT':
      return {
        ...state,
        total: state.total + action.pizzaPrice,
        order: [...action.order]
      }
    default:
      return state;
  }
}


As a result, it turns out that by clicking on the button, redux works correctly, the parent component is re-rendered, but its children are not. How can this be fixed?
Thanks in advance for any help!

Answer the question

In order to leave comments, you need to log in

1 answer(s)
D
Dmitry, 2020-06-12
@Incold

Because you change the count, but don't spread the order element itself, the link remains the same and React thinks nothing has changed
Instead ,
order[index].count = blablabla
write

order[index] = {...order[index], count: blablabla }

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question