gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 17:22:24 26 4
gpt4 key购买 nike

我有以下组件

  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>
)
}
该组件在以下上下文中使用
<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>
在我的电脑上,当鼠标悬停在 ListItem 上时, onMouseEnter激活和控制台日志
onMouseEnter
isActive true
在我的电脑上当鼠标离开 ListItem , onMouseLeave激活和控制台日志
onMouseLeave
isActive false
这里的一切都很好。当我打开导航菜单时,问题出在移动设备上,我控制台日志
isActive false
正如预期的那样。
但是当我点击 ListItem第一次,我控制台日志
onMouseEnter
isActive true
onClick a
isActive false
和我的 ListItem children不要打开。但是当我点击 ListItem我第二次控制台日志
onClick a
isActive true
打开我的 ListItem children .如果我点击 ListItem第三次,我控制台日志
onClick a
isActive false
关闭我的 ListItem children如何解开我的状态变化,以便在我第一次而不是第二次点击时,我的 ListItem children在手机上打开?

最佳答案

这是一个令人惊讶的棘手问题。您可以尝试几种方法。我没有时间亲自尝试它们。

  • 方法一:
    您可以在 <li> 上使用 native 非冒泡事件(mouseenter、mouseleave)。元素。 useEvent 是一个更方便地使用原生事件的钩子(Hook)。 (只需复制代码,因为我还没有决定该库的 future )
  • import React, { useState, useCallback } from 'react';
    import classnames from 'classnames';
    import { useEvent } from 'the/path/to/the/hook';

    const useMouseEnter = (listener, options) => useEvent('mouseenter', listener, options);
    const useMouseLeave = (listener, options) => useEvent('mouseleave', listener, options);

    const ListItem = ({ children, title = '' }) => {

    const [isActive, setIsActive] = useState(false);
    const toggle = () => setIsActive(_ => !_);
    const open = () => setIsActive(true);
    const close = () => setIsActive(false);

    const [setMouseEnterTarget] = useMouseEnter(open); // the setters are stable...
    const [setMouseLeaveTarget] = useMouseLeave(close);
    const setRef = useCallback((element) => {
    setMouseEnterTarget(element);
    setMouseLeaveTarget(element);
    }, []); // ...so we don't need them in the dependencies array

    return (
    <li ref={setRef} className={classnames('depth1', { 'is-active': isActive })}>
    <a href="#" onClick={(e) => {
    console.log('onClick a');
    e.preventDefault();
    toggle();
    }}>{title}</a>
  • 方法二:
    您可以检测是否hover是您当前环境的一项功能,并相应地控制您的代码行为:
  •   const [isActive, setIsActive] = useState(false);
    const toggle = () => setIsActive(_ => !_);
    const open = () => setIsActive(true);
    const close = () => setIsActive(false);
    const supportsHover = useMedia('(hover: hover)');
    const mouseEvents = {
    onMouseEnter: open,
    onMouseLeave: close,
    };

    return (
    <li className={classnames('depth1', { 'is-active': isActive })}
    { ...supportsHover ? mouseEvents : undefined }
    >
    <a href="#" onClick={(e) => {
    console.log('onClick a');
    e.preventDefault();
    toggle();
    }}>{title}</a>
    和钩子(Hook)
    import { useState, useEffect } from 'react';

    export const useMedia = (query) => {
    const [matches, setMatches] = useState(window.matchMedia(query).matches);

    useEffect(() => {
    const media = window.matchMedia(query);
    if (media.matches !== matches) setMatches(media.matches);
    const listener = () => setMatches(media.matches);
    media.addListener(listener);
    return () => media.removeListener(listener);
    }, [matches, query]);

    return matches;
    };
  • 方法3:
    您可以启动一个计时器,例如每次切换后 250 毫秒并忽略进一步切换,直到计时器到期
  • 方法4:
    您可以防止状态在每个 event loop 中多次切换。通过同步设置标志和异步删除标志(因此在下一个事件循环迭代中)
    (但不知道有问题的事件是否在移动设备上同步触发)
  • 关于javascript - 解开 onMouseEnter、onMouseLeave 和 onClick 中的状态变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66758341/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com