setState() doesn't work on first click ! the state value gets updated only on second , third ....clicks. i used proper contexts and imports to handle the states!
I'll quickly summarize what im doing top nav bar has two buttons , home and cart. Side nav bar has three hero buttons, on click renders the respective hero store which has tshirts , socks and shoes with + and - buttons to increase or decrease the quantity.
on each click the value of span that displays the quantity increases correctly but the cart buttons shows the quantity excluding the first clicks. Like when i increment the tshirts value to 1 , the cart button doesn't show any value ,as i increment the tshirts value to 2 the cart button shows 1
cartButton uses the state CartValue tshirts,socks,shoes use the state HeroGoods
(live demo) click here to see the what im talking about
i'm not sure if im allowed to post all the components and external links like github here. but anyways if you guys cant see where i went wrong from the code below , here's link to the github repo
import React , {useState,useEffect}from 'react';
import Navmenu from './Navmenu'
import SideNav from './SideNav'
import ActionDiv from './ActionDiv'
import ActionHeroStore from './ActionHeroStore'
import ActionCart from './ActionCart'
import '../css/main.css'
export const HeroContext=React.createContext()
const emptyGood={
tshirts:0,
shoes:0,
socks:0,
}
const emptyCart={
batman:{
tshirts:0,
shoes:0,
socks:0,
},
superman:{
tshirts:0,
shoes:0,
socks:0,
},
greenlantern:{
tshirts:0,
shoes:0,
socks:0,
},
}
function empty()
{
return null
}
function App() {
const [hero,setHero]=useState(null)
const [cartValue,setCartValue]=useState(emptyCart)
const [batmanGoods,setBatmanGoods]=useState(emptyGood)
const [supermanGoods,setSupermanGoods]=useState(emptyGood)
const [greenLanternGoods,setGreenLanternGoods]=useState(emptyGood)
const [showCart,setShowCart]=useState(false)
function handleUpdateGoods(hero,obj){
hero=='batman'?
setBatmanGoods(prevState=>{
return {...prevState,...obj}
}):
hero=='superman'?
setSupermanGoods(prevState=>{
return {...prevState,...obj}
}):
hero=='greenlantern'?
setGreenLanternGoods(prevState=>{
return {...prevState,...obj}
}):
empty()
}
function handleHeroSelect(name){
setHero(prevState=>prevState=name)
}
function handleCartValue(value)
{
setCartValue(value)
}
function handleShowCart(status)
{
setShowCart(status)
}
function giveHeroGoods(hero,element)
{
return (
hero=='batman'?batmanGoods[element]:
hero=='superman'?supermanGoods[element]:
hero=='greenlantern'?greenLanternGoods[element]:empty()
)
}
function handleUpdateCart(name){
name=='batman'?
setCartValue(prevState=>{
return {...prevState,batman:{...batmanGoods}}
}):
name=='superman'?
setCartValue(prevState=>{
return {...prevState,superman:{...supermanGoods}}
}):
name=='greenlantern'?
setCartValue(prevState=>{
return {...prevState,greenlantern:{...greenLanternGoods}}
}):
empty()
}
const heroContextValue={
handleHeroSelect,
handleCartValue,
handleUpdateGoods,
giveHeroGoods,
handleUpdateCart,
handleShowCart
}
return (
<>
<HeroContext.Provider value={heroContextValue}>
<Navmenu cartValue={cartValue}/>
<div className="mainContent">
<SideNav cartValue={cartValue}/>
{hero==null && !showCart &&<ActionDiv/>}
{hero!==null && !showCart && <ActionHeroStore hero={hero}/>}
{showCart && <ActionCart cartValue={cartValue}/>}
</div>
</HeroContext.Provider>
</>
)
}
export default App;
import React ,{useContext} from 'react'
import {HeroContext} from './App'
export default function Navmenu(props) {
const {cartValue}=props
const {handleHeroSelect,handleShowCart}=useContext(HeroContext)
function giveGoodsSum(obj)
{
return obj.tshirts+obj.socks+obj.shoes
}
function giveCartValue(cartValue){
let sum=0
for(let key in cartValue)
{
sum=sum+giveGoodsSum(cartValue[key])
}
return(
sum!==0?sum:null
)
}
return (
<div
className="navMenu"
>
<button
className="homeButton"
onClick={()=>{
handleHeroSelect(null)
handleShowCart(false)
}}
>
Home
</button>
<button
className="cartButton"
onClick={()=>{
handleHeroSelect(null)
handleShowCart(true)
}}
>
cart
<span
>
{giveCartValue(cartValue)}
</span>
</button>
</div>
)
}
import React ,{useContext} from 'react'
import {HeroContext} from './App'
export default function SideNav() {
const {handleHeroSelect}=useContext(HeroContext)
return (
<div className="sideNav">
<div
className="batman"
onClick={()=>handleHeroSelect('batman')}
/>
<div
className="superman"
onClick={()=>handleHeroSelect('superman')}
/>
<div
className="greenlantern"
onClick={()=>handleHeroSelect('greenlantern')}
/>
</div>
)
}
import React from 'react'
import ActionHeroStoreGoods from './ActionHeroStoreGoods'
export default function ActionHeroStore(props) {
const {hero}=props
return (
<div className={`actionHeroStore ${hero}div`}>
<h3>{hero}</h3>
<div className="actionHeroStore_goods">
<ActionHeroStoreGoods hero={hero}/>
</div>
</div>
)
}
import React, { Fragment,useContext } from 'react'
import {HeroContext} from './App'
export default function ActionHeroStoreGoods({hero}) {
const {giveHeroGoods,
handleUpdateGoods,
handleUpdateCart
}=useContext(HeroContext)
const goods=['tshirts','shoes','socks'];
const goodsElement=goods.map((element,index) => {
return <Fragment key={index}>
<div className="soloGood">
<span>{element}</span>
<button
onClick={
()=>decrement(hero,element)
}>-</button >
<span>{giveHeroGoods(hero,element)}</span>
<button onClick={
()=>{
increment(hero,element)
handleUpdateCart(hero)
}
}>+</button>
</div>
</Fragment>
})
function increment(hero,element){
let updateObj={};
updateObj[element]=giveHeroGoods(hero,element)+1
handleUpdateGoods(hero,updateObj)
}
function decrement(hero,element){
if(giveHeroGoods(hero,element)>0)
{
let updateObj={};
updateObj[element]=giveHeroGoods(hero,element)-1
handleUpdateGoods(hero,updateObj)
}
}
return (
<>
{goodsElement}
</>
)
}