首页 > 解决方案 > react setState() 在第一次点击时不起作用,但在第二、第三次点击时工作正常……点击

问题描述

setState() 在第一次点击时不起作用!状态值仅在第二次、第三次 ....clicks 时更新。我使用适当的上下文和导入来处理状态!

我将快速总结一下我在做什么顶部导航栏有两个按钮,主页和购物车。侧导航栏有三个英雄按钮,点击会呈现相应的英雄商店,其中有 T 恤、袜子和鞋子,带有 + 和 - 按钮来增加或减少数量。

在每次点击时,显示数量的 span 值正确增加,但购物车按钮显示的数量不包括第一次点击。就像当我将 tshirts 值增加到 1 时,购物车按钮不显示任何值,当我将 tshirts 值增加到 2 时,购物车按钮显示 1

cartButton 使用状态 CartValue tshirts,socks,shoes 使用状态 HeroGoods

(现场演示)单击此处查看我在说什么

我不确定我是否允许在此处发布所有组件和外部链接,例如 github。但无论如何,如果你们从下面的代码中看不到我哪里出错了,这里是 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}
        </>        
    )
}

标签: javascriptreactjssetstate

解决方案


问题不在 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){
...
...

推荐阅读