Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

283
Visualizações
useReducer: acción de envío, muestra el estado en otro componente y actualiza el estado cuando se envía la acción

Tengo un problema que no puedo resolver. Estoy creando una aplicación de reacción de comercio electrónico y uso useReducer y useContext para la administración del estado. El cliente abre un producto, elige una cantidad de artículos y luego hace clic en el botón "Agregar al carrito" que envía una acción. Esta parte está funcionando bien y comienza el problema. No sé cómo mostrar y actualizar en el componente Navbar.js una cantidad total de productos en el carrito. Se muestra después de los cambios de ruta, pero quiero que se actualice al hacer clic en el botón Agregar al carrito. Probé useEffect pero no funciona.

el estado inicial se ve así

 const initialState = [ { productName: '', count: 0 } ]

AddToCart.js funciona bien

 import React, { useState, useContext } from 'react' import { ItemCounterContext } from '../../App' function AddToCart({ product }) { const itemCounter = useContext(ItemCounterContext) const [countItem, setCountItem] = useState(0) const changeCount = (e) => { if (e === '+') { setCountItem(countItem + 1) } if (e === '-' && countItem > 0) { setCountItem(countItem - 1) } } return ( <div className='add margin-top-small'> <div className='add-counter' onClick={(e) => changeCount(e.target.innerText)} role='button' > - </div> <div className='add-counter'>{countItem}</div> <div className='add-counter' onClick={(e) => changeCount(e.target.innerText)} role='button' > + </div> <button className='add-btn btnOrange' onClick={() => itemCounter.dispatch({ type: 'addToCart', productName: product.name, count: countItem })} > Add to Cart </button> </div> ) } export default AddToCart

Navbar.js es donde tengo un problema

 import React, { useContext } from 'react' import { Link, useLocation } from 'react-router-dom' import NavList from './NavList' import { StoreContext, ItemCounterContext } from '../../App' import Logo from '../Logo/Logo' function Navbar() { const store = useContext(StoreContext) const itemCounter = useContext(ItemCounterContext) const cartIcon = store[6].cart.desktop const location = useLocation() const path = location.pathname const itemsSum = itemCounter.state .map((item) => item.count) .reduce((prev, curr) => prev + curr, 0) const totalItemsInCart = ( <span className='navbar__elements-sum'> {itemsSum} </span> ) return ( <div className={`navbar ${path === '/' ? 'navTransparent' : 'navBlack'}`}> <nav className='navbar__elements'> <Logo /> <NavList /> <Link className='link' to='/cart'> <img className='navbar__elements-cart' src={cartIcon} alt='AUDIOPHILE CART ICON' /> {itemsSum > 0 ? totalItemsInCart : null} </Link> </nav> </div> ) } export default Navbar
over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

Bueno, ItemCounterContext es importante para este problema, simplemente ignore StoreContext, es para imágenes... Aquí hay una función reductora.

 export const reducer = (state, action) => { // returns -1 if product doesn't exist const indexOfProductInCart = state.findIndex((item) => item.productName === action.productName) const newState = state switch (action.type) { case 'increment': { if (indexOfProductInCart === -1) { newState[state.length] = { productName: action.productName, count: state.count + 1 } return newState } newState[indexOfProductInCart] = { productName: action.productName, count: state.count + 1 } return newState } case 'decrement': { if (indexOfProductInCart === -1) { newState[state.length] = { productName: action.productName, count: state.count - 1 } return newState } newState[indexOfProductInCart] = { productName: action.productName, count: state.count - 1 } return newState } case 'addToCart': { if (indexOfProductInCart === -1) { newState[state.length] = { productName: action.productName, count: action.count } return newState } newState[indexOfProductInCart] = { productName: action.productName, count: action.count } return newState } case 'remove': return state.splice(indexOfProductInCart, 1) default: return state } }

Y aquí está App.js donde comparto el estado con otros componentes

 import React, { createContext, useMemo, useReducer } from 'react' import { BrowserRouter as Router, Routes, Route } from 'react-router-dom' import Navbar from './components/Navbar/Navbar' import Homepage from './pages/Homepage/Homepage' import Footer from './components/Footer/Footer' import ErrorPage from './pages/ErrorPage/ErrorPage' import SelectedCategory from './pages/SelectedCategory/SelectedCategory' import SingleProduct from './pages/SingleProduct/SingleProduct' import ScrollToTop from './services/ScrollToTop' import store from './services/data.json' import { reducer } from './services/ItemCounter' import './scss/main.scss' export const StoreContext = createContext(store) export const ItemCounterContext = createContext() function App() { const initialState = [{ productName: '', count: 0 }] const [state, dispatch] = useReducer(reducer, initialState) const counter = useMemo(() => ({ state, dispatch }), []) return ( <div className='app'> <StoreContext.Provider value={store}> <ItemCounterContext.Provider value={counter}> <Router> <ScrollToTop /> <Navbar /> <Routes> <Route path='/' element={<Homepage />} /> <Route path='/:selectedCategory' element={<SelectedCategory />} /> <Route path='/:selectedCategory/:singleProduct' element={<SingleProduct />} /> <Route path='*' element={<ErrorPage />} /> </Routes> <Footer /> </Router> </ItemCounterContext.Provider> </StoreContext.Provider> </div> ) } export default App
over 4 years ago · Santiago Trujillo Relatório

0

El problema está en su reductor, particularmente donde asigna el estado anterior al estado newState para hacer mutaciones y devolver el estado actualizado. En JavaScript, los no primitivos se refieren por dirección y no por valor. Dado que su initialState que es una matriz, no es primitivo, por lo que cuando asigna un no primitivo a una nueva variable, esta variable solo apunta a la matriz existente en la memoria y no crea una nueva copia. Y, en React, las actualizaciones se activan/transmiten solo cuando se reconstruye un estado (así es como React entiende que hay una actualización) y no muta suavemente. Cuando muta y devuelve newState , básicamente está mutando el state existente y no haciendo que se reconstruya. Una solución rápida para esto sería copiar su state en newState y no simplemente asignarlo. Esto podría hacerse usando el operador de propagación ( ... ).
En su función reductora, cambie:

 const newState = state

para

 const newState = [...state]

Su función reductora debería verse así:

 export const reducer = (state, action) => { // returns -1 if product doesn't exist const indexOfProductInCart = state.findIndex((item) => item.productName === action.productName) const newState = [...state] //Deep-copying the previous state switch (action.type) { case 'increment': { if (indexOfProductInCart === -1) { newState[state.length] = { productName: action.productName, count: state.count + 1 } return newState } newState[indexOfProductInCart] = { productName: action.productName, count: state.count + 1 } return newState } case 'decrement': { if (indexOfProductInCart === -1) { newState[state.length] = { productName: action.productName, count: state.count - 1 } return newState } newState[indexOfProductInCart] = { productName: action.productName, count: state.count - 1 } return newState } case 'addToCart': { if (indexOfProductInCart === -1) { newState[state.length] = { productName: action.productName, count: action.count } return newState } newState[indexOfProductInCart] = { productName: action.productName, count: action.count } return newState } case 'remove': return state.splice(indexOfProductInCart, 1) default: return state } }
over 4 years ago · Santiago Trujillo Relatório

0

Sé exactamente de qué estás hablando, pero el problema en el reductor es que solo los métodos mutativos funcionan en el estado. Los métodos inmutables como .slice(), .concat() o incluso el operador de propagación [...state] no funcionan y no sé por qué :( probé ambas respuestas, pero dispatch(action) no funciona cambiar el estado Tal vez el estado inicial es el problema, intentaré ponerlo así

estadoInicial = { carrito: [nombreProducto: '', cuenta: 0] }

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda