Как не перезаписать состояние Redux при отправке

#reactjs #redux

Вопрос:

поэтому я пытаюсь отправить несколько объектов, а затем отобразить их. Проблема в том, что вместо добавления нового объекта в массив я перезаписываю их, и он меняется на новый. Итак, у меня есть несколько продуктов, которые являются отдельными объектами. Я помещаю их в массив и отправляю массив сюда:

 function Product({ id, title, image, price, rating }) {
  const [items, setItems] = useState([]);
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(
      pushItems({
        items,
      })
    );
    console.log(items);
  }, [items]);

  return (
    <div className="product">
      <div className="product__Info">
        <p>{title}</p>
        <p className="product__Info__price">
          <small>

lt;/small>
<strong>{price}</strong>
</p>
<div className="product__Info__rating">
{Array(rating)
.fill()
.map((_, i) => (
<p>⭐</p>
))}
</div>
</div>
<img src={image} alt="" />
<button
onClick={(e) =>
setItems({
title,
image,
price,
rating,
})
}
>
Add to basket
</button>
</div>
);
}

и вот как выглядит мой редуктор, в котором, я думаю, проблема:

 import { createSlice } from "@reduxjs/toolkit";

const checkoutSlice = createSlice({
  name: "checkout",
  initialState: {
    items: null,
  },
  reducers: {
    pushItems: (state, action) => {
      state.items = [...state.items, action.payload.items];
    },
  },
});

export const { pushItems } = checkoutSlice.actions;
export const selectItems = (state) => state.checkout.items;

export default checkoutSlice.reducer;
 

Я знаю, как это сделать «по-старому», но когда я использую срезы, я немного сбит с толку.

Ответ №1:

Вашему компоненту продукта не нужно хранить массив элементов, вы можете напрямую обновить массив элементов в магазине redux

 function Product({ id, title, image, price, rating }) {
  const dispatch = useDispatch();

  const onAddItem = (item) => {
      dispatch(pushItems({item}));
  }

  return (
    <div className="product">
      <div className="product__Info">
        <p>{title}</p>
        <p className="product__Info__price">
          <small>

lt;/small>
<strong>{price}</strong>
</p>
<div className="product__Info__rating">
{Array(rating)
.fill()
.map((_, i) => (
<p>⭐</p>
))}
</div>
</div>
<img src={image} alt="" />
<button
onClick={(e) =>
onAddItem({
title,
image,
price,
rating,
})
}
>
Add to basket
</button>
</div>
);
}

Также обратите внимание, что обновление состояния внутри redux-toolkit среза не должно заботиться о неизменности, поскольку оно используется внутри immer .

Вы можете обновить свое состояние восстановления, как показано ниже:

 const checkoutSlice = createSlice({
  name: "checkout",
  initialState: {
    items: null,
  },
  reducers: {
    pushItems: (state, action) => {
      state.items.push(action.payload.item);
    },
  },
});
 

Комментарии:

1. Я предполагаю, что ваш способ похож на мой, поэтому, когда я пытаюсь сделать это таким образом: pushItems: (state, action) => { state.items = action.payload.items; , это перезаписывает мое состояние.

2. нажатие отличается от прямой замены. Как я уже упоминал, вам нужно использовать state.items.push(action.payload.item) Также обратите внимание, что я также изменил внутренний код продукта

3. Я пытался сделать это, как ты сказал, и я получаю Actions may not have an undefined "type" property. Have you misspelled a constant? , Когда я пытаюсь dispatch(pushItems({item)}) , я получаю Cannot read property 'push' of null

4. О, и в исходном состоянии должен быть массив { items: [] } вместо { items: null } @larryfisherman, который исправит вашу ошибку

5. @LindaPaiste Спасибо, что указал на это. Я обновил свой ответ.