React useState 似乎不适用于事件监听器(Next.js)

问题描述 投票:0回答:1

我正在尝试创建一个网页,该网页的右上角有一个固定的汉堡包图标,单击时会打开一个导航栏。如果用户在导航栏之外单击,则导航栏应关闭并且汉堡包图标应再次出现。

我使用 nextjs,而 nextjs 不接受服务器端组件中的用户交互,因此我必须打开另一个名为 CrMenuWrapper 的文件。

'use client'
import logger from '@/utils/logger'
import { NextPage } from 'next'
import { useEffect, useRef, useState } from 'react'

interface Props { }

const CrMenuWrapper: NextPage<Props> = ({ }) => {

    const [isMenuClicked, setIsMenuClicked] = useState(false)
    const phoneMenu: React.RefObject<HTMLDivElement> = useRef(null)
    const menuButton: React.RefObject<HTMLDivElement> = useRef(null)

    logger(isMenuClicked)


    function handleOnClick(e: any) {
        
        if (phoneMenu.current && isMenuClicked && !phoneMenu.current.contains(e.target)) {
            setIsMenuClicked(prevIsMenuClicked => !prevIsMenuClicked)
        } else if (menuButton.current && !isMenuClicked && menuButton.current.contains(e.target)) {
            logger("clicked")
            setIsMenuClicked(prevIsMenuClicked => !prevIsMenuClicked)
        }
    }

    useEffect(() => {
        document.addEventListener('click', (e) => handleOnClick(e))
        return () => {
            document.removeEventListener('click', (e) => handleOnClick(e))
        };
    }, [])

    return <div>
        <div ref={phoneMenu} className={`fixed z-50 bg-gradient-to-bl from-violet-600/30 backdrop-blur-sm to-indigo-600/30  bg-no-repeat bg-top top-0 right-0 transition-all border-2 border-[var(--secondary-rgb)] 
        w-[75vw] aspect-square rounded-es-full md:hidden origin-top-right duration-300 
        ${isMenuClicked ? " scale-100 rotate-0" : " scale-0 rotate-45"}`}>

        </div>
        <div ref={menuButton} className={` bg-transparent md:hidden fixed aspect-square h-12 top-10 backdrop-blur-md right-10 stroke-0 hover:cursor-pointer
        border-[var(--secondary-rgb)] p-2.5 rounded-full border-2 hover:scale-125 transition-all  opacity-70 hover:opacity-100
        ${isMenuClicked ? " scale-0" : " scale-100"}`}>
            <svg id="nav-svg" stroke="currentColor" fill="currentColor" className={`fill-[var(--primary-rgb)] 
            `} viewBox="0 0 24 24" height="inherit" width="inherit" xmlns="http://www.w3.org/2000/svg"><path id="nav-path" d="M16 18V20H5V18H16ZM21 11V13H3V11H21ZM19 4V6H8V4H19Z"></path></svg>
        </div>
    </div>
}

export default CrMenuWrapper

CrMenuWrapper.tsx

问题是当单击按钮时,它将按钮缩放到 0 并打开导航栏;但是,当我尝试单击导航之外时,它不会关闭。此外,当我在handleOnClick 内部记录 isMenuClicked 时,它会记录 false;然而,当我把它放在上面时(如上所示),它记录为 true,然后不会自行更新。

我的 10 倍编码器可以帮我解决这个问题吗?

谢谢,

javascript reactjs state addeventlistener next
1个回答
0
投票

嗯,

我自己解决了这个问题,对于那些想知道的人:

您所要做的就是将

isMenuClicked
添加为

的输入
 useEffect(() => {
        document.addEventListener('click', (e) => handleOnClick(e))
        return () => {
            document.removeEventListener('click', (e) => handleOnClick(e))
        };
    }, [])

因此它应该看起来像这样:

 const [isMenuClicked, setIsMenuClicked] = useState(false)

//extra code bla bla bla ...

 useEffect(() => {
        document.addEventListener('click', (e) => handleOnClick(e))
        return () => {
            document.removeEventListener('click', (e) => handleOnClick(e))
        };
    }, [isMenuClicked])

事件侦听器的工作方式可能是保持状态,除非您另有说明。

谢谢。

© www.soinside.com 2019 - 2024. All rights reserved.