javascript - react setState()不适用于第一次单击,但在第二次,第三次…单击时工作正常

标签 javascript reactjs setstate

setState()在第一次单击时不起作用!状态值仅在第二,第三.... clicks上更新。我使用适当的上下文和导入来处理状态!
我将快速总结一下我正在执行的顶部导航栏有两个按钮,即主页和购物车。
侧面导航栏具有三个英雄按钮,单击可渲染相应的英雄商店,其中包含带有+和-按钮的T恤, socks 和鞋子,以增加或减少数量。
每次单击时,显示数量的跨度值会正确增加,但购物车按钮会显示数量(不包括首次点击)。就像当我将T恤的值增加到1时,购物车按钮不显示任何值,当我将T恤的值增加到2时,购物车按钮显示1
cartButton使用状态CartValue
T恤, socks ,鞋子使用状态HeroGoods
(live demo) click here 看我在说什么
我不确定即时通讯是否允许在此处发布所有组件和外部链接(如github)。但是无论如何,如果你们不能从下面的代码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}
        </>        
    )
}

最佳答案

问题不在setState中。代码中的问题。在* Goods状态更改之前,将调用handleUpdateCart()函数。因此,它适用于旧数据。如果要在“App.js”文件中添加以下片段:

...
...
  function giveHeroGoods(hero,element)
  {
    return (
    hero=='batman'?batmanGoods[element]:
    hero=='superman'?supermanGoods[element]:
    hero=='greenlantern'?greenLanternGoods[element]:empty()
    )
  }
// FROM HERE
  React.useEffect(() => {
    handleUpdateCart('batman');
  }, [
    batmanGoods
  ]);

  React.useEffect(() => {
    handleUpdateCart('superman');
  }, [
    supermanGoods
  ]);

  React.useEffect(() => {
    handleUpdateCart('greenlantern');
  }, [
    greenLanternGoods
  ]);

// TILL HERE
  function handleUpdateCart(name){
...
...

关于javascript - react setState()不适用于第一次单击,但在第二次,第三次…单击时工作正常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62585711/

相关文章:

javascript - 为什么我的 index.html 页面加载很慢

javascript - AngularJS - 点击事件(在指令中)在父级的任何地方被点击时触发

reactjs - React Native Expo 离线应用 : How to Update Local Database from Remote Server

javascript - 如何使用 npm 脚本编辑 css 文件中的相对路径?

javascript - 为什么在异步调用的构造函数中使用 setState 时此组件不更新 - ReactJS/ReactNative?

javascript - 动态调整网页大小

javascript - 无法使用带有解析存在 View 模型的 ko.mapping.fromJSON 解析绑定(bind) js 错误

reactjs - 看来您正在将关键帧声明(hVshE)插入到未标记的字符串中

javascript - 无法使用绑定(bind)到 `this.setState` 的对象文字调用 `partialState`,因为字符串 [1] 与字符串文字 [2] 不兼容

javascript - 在 await 之后调用 setState 时状态立即可用