Solucionado (ver solução)
Solucionado
(ver solução)
3
respostas

Erro na hora de incrementar quantidade.

Estou com um erro, que não conseguir entender, depois que fazer todas as alterações o site abriu, porem na hora de incrementar a quantidade dos produtos, como: clicando pra adicionar o meus item no carrinho, ou clicando no botão de ( + ) para aumentar a quantidade, ele dá erro:

TypeError: Cannot read properties of undefined (reading 'quantidade')
    at dados.reduce.quantidadeTemp (index.jsx:19:61)
    at Array.reduce (<anonymous>)
    at index.jsx:17:18
    at updateMemo (react-dom.development.js:17246:19)
    at Object.useMemo (react-dom.development.js:17886:16)
    at useMemo (react.development.js:1650:21)
    at MeuProvider (index.jsx:16:41)
    at renderWithHooks (react-dom.development.js:16305:18)
    at updateFunctionComponent (react-dom.development.js:19588:20)
    at beginWork (react-dom.development.js:21601:16)

index.js da pasta context:

import { createContext, useReducer, useState } from "react";
import { carrinhoReducer } from "@/components/Reducer/carrinhoRedcuer";
import { useMemo } from "react";
import { useEffect } from "react";

export const Contexto = createContext();
Contexto.displayName = "ContextoCarrinho"

const estadoInicial = []

export const MeuProvider = ({ children }) => {
  const [dados, dispatch] = useReducer(carrinhoReducer, estadoInicial)
  const [quantidade, setQuantidade] = useState(0)
  const [valorTotal, setValorTotal] = useState(0)

  const { totalTemp, quantidadeTemp } = useMemo(() => {
    return dados.reduce(
      (acumulador, produto) => ({
        quantidadeTemp: acumulador.quantidadeTemp + produto.quantidade,
        totalTemp: acumulador.totalTemp + produto.preco * produto.quantidade,
      }),
      {
        quantidadeTemp: 0,
        totalTemp: 0,
      }
    );
  }, [dados]);

  useEffect(() => {
    setQuantidade(quantidadeTemp);
    setValorTotal(totalTemp);
  });

  return (
    <Contexto.Provider value={{dados, dispatch, quantidade, setQuantidade, valorTotal, setValorTotal}}>
      { children }
    </Contexto.Provider>
  )
}

carrinhoReduce.js:

export const ADD_PRODUTO = "ADD_PRODUTO"
export const REMOVE_PRODUTO = "REMOVE_PRODUTO"
export const UPDATE_QUANTIDADE = "UPDATE_QUANTIDADE"

export const carrinhoReducer = (state, action) =>{
  switch (action.type){
    case ADD_PRODUTO:
      const novoProduto = action.payload
      const produto = state.findIndex( item => item.id === novoProduto.id )
      if (produto === -1) {
          novoProduto.quantidade = 1;
          return [...state, novoProduto]
      } else {
        return state.map((item, index) => {
          index === produto
            ? { ...item, quantidade: item.quantidade + 1}
            : item
        })
      };
  
      case REMOVE_PRODUTO:
        const produtoId = action.payload;
        return state.filter(item => item.id != produtoId);
      
      case UPDATE_QUANTIDADE:
        const {produtoId: id, quantidade} = action.payload
        return state.map(item => 
          item.produto = id && quantidade > 1 ? {...item, quantidade: item.quantidade} : item
        );

      default: 
        return state
    }
}

useCarrinhoRedux.js:

import ItemCarrinho from "../components/ItemCarrinho";
import { Contexto } from "../context";
import { useContext } from "react";
import {
  ADD_PRODUTO,
  REMOVE_PRODUTO,
  UPDATE_QUANTIDADE,
} from "../components/Reducer/carrinhoRedcuer";

const addProdutoAction = (novoProduto) => ({
  type: ADD_PRODUTO,
  payload: novoProduto,
});

const removeProdutoAction = (produtoId) => ({
  type: REMOVE_PRODUTO,
  payload: produtoId,
});

const updateQuantidadeAction = (produtoId, quantidade) => ({
  type: UPDATE_QUANTIDADE,
  payload: {produtoId, quantidade},
});

export const useCarrinhoContext = () => {
  const { dados, dispatch, quantidade, valorTotal } = useContext(Contexto);

  function adicionarProduto(novoProduto) {
    dispatch(addProdutoAction(novoProduto))
  }

  function removerProdutoCarrinho(id) {
    const produto = dados.find(item => item.id === id);

    if (produto && produto.quantidade > 1) {
      dispatch(updateQuantidadeAction(id, produto.quantidade - 1))
    } else { 
      dispatch(removeProdutoAction(id))
    }
  }

  function removerProduto (id) {
    dispatch(removeProdutoAction(id))
  }

  return {
    dados,
    adicionarProduto,
    removerProduto,
    removerProdutoCarrinho,
    valorTotal,
    quantidade,
  };
};

Já alterei tudo que estava ao alcance do meu conhecimento, mas devo ter passado alguma coisa

3 respostas
solução!

Fala Daivis, beleza ? Acredito que saiba qual é o problema. Notei que falta a palavra chave return dentro do map que você realiza no state, conforme sinalizado no trecho de código abaixo, referente ao arquivo carrinhoReduce.js:

export const carrinhoReducer = (state, action) =>{
  switch (action.type){
    case ADD_PRODUTO:
      const novoProduto = action.payload
      const produto = state.findIndex( item => item.id === novoProduto.id )
      if (produto === -1) {
          novoProduto.quantidade = 1;
          return [...state, novoProduto]
      } else {
        return state.map((item, index) => {
        // Acresente o return na linha abaixo
  /* ----> */  return index === produto
            ? { ...item, quantidade: item.quantidade + 1}
            : item
        })
      };

Segue a explicação:

1 - Quando você tenta acrescentar um produto já existente no carrinho, o código entra neste bloco else e executa o map, porém como não tem o return explícito, a sua função carrinhoReducer retorna undefined ao invés de retornar o novo estado atualizado com a quantidade atualizada.

2- Como consequência, isso implica na sua variável de estado dados armazenar o undefined após o término da execução da função carrinhoReducer.

3- Posteriormente, no arquivo index.js, o método reduce então é executado em cima da sua varíavel de estado dados ( que é undefined ) . Logo o produto dentro desse método reduce também é undefined e o erro é lançado ao tentar acessar a propriedade quantidade do produto cujo valor é undefined.

Detalhes e comentários no seu arquivo index.js da pasta context:

export const MeuProvider = ({ children }) => {
  const [dados, dispatch] = useReducer(carrinhoReducer, estadoInicial)
  const [quantidade, setQuantidade] = useState(0)
  const [valorTotal, setValorTotal] = useState(0)

  const { totalTemp, quantidadeTemp } = useMemo(() => {
  // Abaixo dados é undefined
    return dados.reduce(
    // Abaixo produto é undefined
      (acumulador, produto) => ({
      // Nessa linha o erro ocorre em produto.quantidade
        quantidadeTemp: acumulador.quantidadeTemp + produto.quantidade,
        totalTemp: acumulador.totalTemp + produto.preco * produto.quantidade,
      }),
      {
        quantidadeTemp: 0,
        totalTemp: 0,
      }
    );
  }, [dados]);

Conserta com o return conforme orientado e verifica se o erro deixa de acontecer.

Estou acompanhando o tópico para saber se o erro foi sanado ou se precisar de mais algum esclarecimento!

Abraço e bons estudos!

Opa Ricardo, Descobrir que era 2 problemas, um deles sendo realmente a questão do retorno, e o outro foi a falta de atenção mesmo ksksks

na parte do carrinhoreduce havia um erro de lógica, na hora de atualizar a quantidade em vez de fazer a verificação se o ID do item existia, eu acabei confundindo as propriedades e adicionei uma propriedade que não existia, "item.produto" oque não validava a chamada da função e caia em erro na hora de atualizar a quantidade, pelo menos foi assim que entendi, kkssks fiz essas duas alterações e deu certo.

export const ADD_PRODUTO = "ADD_PRODUTO"
export const REMOVE_PRODUTO = "REMOVE_PRODUTO"
export const UPDATE_QUANTIDADE = "UPDATE_QUANTIDADE"

export const carrinhoReducer = (state, action) =>{
  switch (action.type){
    case ADD_PRODUTO:
      const novoProduto = action.payload
      const produto = state.findIndex( item => item.id === novoProduto.id )
      if (produto === -1) {
          novoProduto.quantidade = 1;
          return [...state, novoProduto]
      } else {
        return state.map((item, index) => {
          index === produto
            ? { ...item, quantidade: item.quantidade + 1}
            : item
        })
      };
  
      case REMOVE_PRODUTO:
        const produtoId = action.payload;
        return state.filter(item => item.id != produtoId);
      
      case UPDATE_QUANTIDADE:
        const {produtoId: id, quantidade} = action.payload
        return state.map(item => 
// ao inves de verificar se o id do item é igual o que está retornando eu acabei incluindo um propriedade inexistente, oque não permitia a verificação, e não fazia a chamada da quantidade quando acionada //
 /* ====> */   item.produto = id && quantidade > 1 ? {...item, quantidade: item.quantidade} : item
        );

      default: 
        return state
    }
}

Hahahahaha, faz parte e muito bem observado, se você não falasse eu não notaria o segundo ! Quanto mais bug resolvido, mais experiência e prática acumulada como dev pra gente, não é? Segue firme nos estudos, abraço!