解开 onMouseEnter、onMouseLeave 和 onClick 中的状态变化

dev*_*_el 5 javascript reactjs

我有以下组件

  const ListItem = ({ children, title = '' }) => {
    const [isActive, setIsActive] = useState(false)

    useEffect(() => {
      console.log('isActive', isActive)
    }, [isActive])

    return (
      <li className={`depth1${(isActive ? ' is-active' : '')}`} onMouseEnter={() => {
        console.log('onMouseEnter')
        setIsActive(true)
      }} onMouseLeave={() => {
        console.log('onMouseLeave')
        setIsActive(false)
      }}>
        <a href="#" onClick={(e) => {
          console.log('onClick a')
          e.preventDefault()
          setIsActive(!isActive)
        }}>{title}</a>
        {isActive && (
          <ul onClick={() => {
            console.log('onClick ul')
            setIsActive(!isActive)
          }}>
            {children}
          </ul>
        )}
      </li>
    )
  }
Run Code Online (Sandbox Code Playgroud)

该组件在以下上下文中使用

<ul>
  <ListItem title="BRAND">
    <li>
      <a href="#" onClick={(e) => {
        e.preventDefault()
      }}>Link</a>
    </li>
    <li>
      <a href="#" onClick={(e) => {
        e.preventDefault()
      }}>Link</a>
    </li>
    <li>
      <a href="#" onClick={(e) => {
        e.preventDefault()
      }}>Link</a>
    </li>
  </ListItem>
  <ListItem title="SERVICE">
    <li>
      <a href="#" onClick={(e) => {
        e.preventDefault()
      }}>Link</a>
    </li>
    <li>
      <a href="#" onClick={(e) => {
        e.preventDefault()
      }}>Link</a>
    </li>
  </ListItem>
  <ListItem title="CLIENT">
    <li>
      <a href="#" onClick={(e) => {
        e.preventDefault()
      }}>Link</a>
    </li>
  </ListItem>
  <ListItem title="CONTENTS">
    <li>
      <a href="#" onClick={(e) => {
        e.preventDefault()
      }}>Link</a>
    </li>
  </ListItem>
</ul>
Run Code Online (Sandbox Code Playgroud)

在我的 PC 上,当鼠标悬停在 a 上时ListItemonMouseEnter激活和控制台日志

onMouseEnter
isActive true
Run Code Online (Sandbox Code Playgroud)

在我的 PC 上,当鼠标离开时ListItemonMouseLeave激活和控制台日志

onMouseLeave
isActive false
Run Code Online (Sandbox Code Playgroud)

这里一切正常。当我打开导航菜单时,问题出在移动设备上,我控制台日志

isActive false
Run Code Online (Sandbox Code Playgroud)

正如预期的那样。

但是当我ListItem第一次点击 a时,我控制台日志

onMouseEnter
isActive true
onClick a
isActive false
Run Code Online (Sandbox Code Playgroud)

而我的ListItem children不打开。但是当我ListItem第二次点击控制台日志时

onClick a
isActive true
Run Code Online (Sandbox Code Playgroud)

这打开了我的ListItem children. 如果我ListItem第三次点击,我会控制台日志

onClick a
isActive false
Run Code Online (Sandbox Code Playgroud)

这关闭了我的 ListItem children

我如何解开我的状态更改,以便在我的第一次而不是第二次点击时,我ListItem children在移动设备上打开?

dev*_*_el 0

我发现很难理清这些状态,所以我用以下方法解决了这个问题

const [isMobileNav, setIsMobileNav] = useState(false)

const windowWidthOnLoad = () => {
  const browser = window.innerWidth
  if (browser <= 1024) {
    setIsMobileNav(true)
  } else {
    setIsMobileNav(false)
  }
}

const windowWidthOnResize = () => {
  const browser = window.innerWidth
  if (browser <= 1024) {
    setIsMobileNav(true)
  } else {
    setIsMobileNav(false)
  }
}

useEffect(() => {
  windowWidthOnLoad()
  window.addEventListener('resize', windowWidthOnResize)
}, [])

const ListItem = ({ children, title = '' }) => {
  const [isActive, setIsActive] = useState(false)

  return (
    <>
      {/* click link once to show ListItem children on mobile */}
      {isMobileNav
        ? <li className={`depth1${(isActive ? ' is-active' : '')}`}>
          <a href="#" onClick={(e) => {
            e.preventDefault()
            setIsActive(!isActive)
          }}>{title}</a>
          {isActive && (
            <ul onClick={() => {
              setIsActive(!isActive)
            }}>
              {children}
            </ul>
          )}
        </li>
        : <li className={`depth1${(isActive ? ' is-active' : '')}`} onMouseEnter={() => {
          setIsActive(true)
        }} onMouseLeave={() => {
          setIsActive(false)
        }}>
          <a href="#" onClick={(e) => {
            e.preventDefault()
            setIsActive(!isActive)
          }}>{title}</a>
          {isActive && (
            <ul onClick={() => {
              setIsActive(!isActive)
            }}>
              {children}
            </ul>
          )}
        </li>
      }
    </>
  )
}
Run Code Online (Sandbox Code Playgroud)