简体   繁体   中英

why my react hook state only update after two clicks

import React, { useState, useEffect } from 'react'
import './mobileNavBar.scss'
import { div } from 'react-router-dom'
import URL from '../../constant/urls'
import { openMobileMenu } from 'component/sideMenu/action/sideMenuAction'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import classnames from 'classnames'

const MobileNavBar = () => {
    const [state, setState] = useState({
        home: true,
        cat: false,
        checkout: false,
    })
    useEffect(() => {
        detectLink()
    }, [])
    const detectLink = () => {
        const path = window.location.pathname
        if (path == '/') {
            setState((current) => ({
                ...current,
                home: true,
                cat: false,
                checkout: false,
            }))
            return
        }
        if (path.includes('cat')) {
            setState((current) => ({
                ...current,
                home: false,
                cat: true,
                checkout: false,
            }))
            return
        }
        if (path.includes('checkout')) {
            setState((current) => ({
                ...current,
                home: false,
                cat: false,
                checkout: true,
            }))
            return
        }
    }
    const handleClick = () => {
        detectLink()
    }
    const homecss = classnames({ active: state.home })
    const catcss = classnames({ active: state.cat })
    const checkoutcss = classnames({ active: state.checkout })
    return (
        <div className="mobileNav">
            <Link to='/' onClick={handleClick} className={'item ' + homecss}></Link>
            <Link to='/cat' onClick={handleClick} className={'item ' + catcss}></Link>
            <Link to='/checkout' onClick={handleClick} className={'item ' + checkoutcss}></Link>
        </div>
    )
}

I got a menu look like this. I want when I click the menu item, css class active will be assigned to the item.

problem is, one click will not make that happen, I need to double click. it seems the state is lagging, it seems it only updates when I trigger the next action.

My guess is that window.location.pathname is not updated before the render. But there's a lot wrong w/ this code. Your useEffect has a lot of dependencies that you're not declaring.

What I'd do is move detectLink to inside the effect, and have it run whenever window.location.pathname has changed. Then change your onClick to deal with the routing (wherever that code is, since it isn't in this example)

ETA:

useEffect(() => {

    const detectLink = () => {
        const path = window.location.pathname
        if (path == '/') {
            setState((current) => ({
                ...current,
                home: true,
                cat: false,
                checkout: false,
            }))
            return
        }
        if (path.includes('cat')) {
            setState((current) => ({
                ...current,
                home: false,
                cat: true,
                checkout: false,
            }))
            return
        }
        if (path.includes('checkout')) {
            setState((current) => ({
                ...current,
                home: false,
                cat: false,
                checkout: true,
            }))
            return
        }
    }

    detectLink()
}, [window.location.pathname])

Then remove your click handler, since this will now run whenever the location changes since you're using Links

Your problem is that you're listening for changes in pathname which isn't immediately updated after click on Link . Wrap your component with withRouter and listen for changes in location.pathname

import { withRouter } from 'react-router-dom'
export const NavMenu = withRouter(({ location, history, match }) =>{
    useEffect(() => detectLink(), [location])
})

And inside detectLink

const detectLink = () => {
    const path = location.pathname
    if (path == '/') {
        setState((current) => ({
            ...current,
            home: true,
            cat: false,
            checkout: false,
        }))
        return
    }
    if (path.includes('cat')) {
        setState((current) => ({
            ...current,
            home: false,
            cat: true,
            checkout: false,
        }))
        return
    }
    if (path.includes('checkout')) {
        setState((current) => ({
            ...current,
            home: false,
            cat: false,
            checkout: true,
        }))
        return
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM