Установить состояние в цикле React Native

У меня есть реквизиты в виде массива объектов, которые я использую для обновления состояния своих элементов. Я могу перебирать объекты и создавать объекты, содержащие product_id и количество. Когда я просто использую console.log, я вижу правильные данные, однако, когда я пытаюсь обновить состояние, я получаю сообщение об ошибке "Too many re-renders, react limits the number of renders to prevent an infinite-loop."

 const [items, setItems] = useState(
    {
      product_id: 93,
      quantity: 2,
    },
    {
      product_id: 22,
      variation_id: 23,
      quantity: 1,
    },
  );
  const cart = props.cart;
  Object.keys(cart).forEach(function (key) {
    const prod = {
      product_id: cart[key].id,
      quantity: cart[key].quantity,
    };
    setItems((currentItems) => {
      return {prod, ...currentItems};
    });
  });

Edit My cart props извлекается из redux с помощью следующего кода

function mapStateToProps(state) {
  return {
    cart: state.cart,
  };
}
export default connect(mapStateToProps)(Checkout);

Проблема в том, что у этой опоры больше атрибутов, чем просто количество и идентификатор, которые мне нужны.


person anonymous    schedule 28.07.2020    source источник
comment
Какое значение передается в качестве опоры тележки?   -  person Moshe Sommers    schedule 28.07.2020
comment
Когда вы выполняете setState, ваш компонент затем будет pretender, что приведет к повторному запуску вашего цикла forEach, который перейдет в setState, который вызовет повторную визуализацию и так далее. Вы можете обернуть это forEach в useEffect (который имеет обратный вызов и зависимости в качестве параметров). Если вы передадите пустой массив в качестве зависимостей, это произойдет только один раз.   -  person Trisma    schedule 28.07.2020
comment
Почему вы устанавливаете состояние, а не просто отрисовываете со значениями свойств?   -  person Moshe Sommers    schedule 28.07.2020
comment
Опора корзины использует опору redux и функцию MapStateToProp. Я не могу просто отобразить его в состоянии, потому что в нем есть дополнительные данные, которые мне не нужны. Мне просто нужно вытащить из него идентификатор и количество.   -  person anonymous    schedule 28.07.2020
comment
Вы не можете вызвать setItems() на глобальном уровне компонента. Оберните код обновления состояния внутри функции, а затем вызовите эту функцию на основе события (например, onClick, onChange или чего-то подобного). Более того, обновлять состояние внутри forEach - не лучшая идея. Просто пропустите массив и в конце обновите состояние.   -  person Faraz Ahmad    schedule 28.07.2020


Ответы (2)


Вам не нужно снова и снова задавать состояние в цикле. Скорее просто зацикливайтесь на массиве, получите элементы и, наконец, установите состояние

   const [items, setItems] = React.useState(
    {
      product_id: 93,
      quantity: 2
    },
    {
      product_id: 22,
      variation_id: 23,
      quantity: 1
    }
  );

  const { cart } = props;
  useEffect(() => {
    const products = Object.entries(cart).map(([key, { id, quantity }]) => ({
      product_id: id,
      quantity: quantity
    }));
    setItems(currentItems => ({ ...products, ...currentItems }));
  }, [cart]);
person brijesh-pant    schedule 28.07.2020

В качестве состояния следует использовать массив или объект. вы передаете в useState два отдельных объекта, оборачивая их в объект с соответствующими ключами. или используйте массив.

it seems you have forgotten to add a wrap your initial object inside curly braces.  

const [items, setItems] = useState([
  {
    product_id: 93,
    quantity: 2,
  },
  {
    product_id: 22,
    variation_id: 23,
    quantity: 1,
  },
]);  

тогда

return [prod, ...currentItems];  

в качестве предложения:
лучше создавать новые объекты и сразу устанавливать их в состояние.

const objectsToAdd = Object.values(cart).map(function (cartItem) {
  return {
    product_id: cartItem.id,
    quantity: cartItem.quantity,
  };
});

setItems((currentItems) => {
  return [...objectsToAdd, ...currentItems];
})
person Kavian Rabbani    schedule 28.07.2020