父组件onScroll事件无法调用子组件函数问题求助
问题描述
子组件内通过onScroll调用HeadlessUI Menu的close函数能正常关闭菜单,但把该函数传递到父组件后,父组件的onScroll调用就失效了。
错误原因分析
- 父组件未执行关闭函数:父组件的
onScroll回调里只是访问了sidebarMenuElementRef.current,但没有调用这个函数,自然不会触发菜单关闭操作。 - 子组件Ref赋值逻辑错误:
MenuButton的ref属性是用来获取DOM元素的,不能直接用来存储close函数,这种赋值方式无效,导致menuButtonElementRef.current无法正确拿到close函数。 - 多组件Ref冲突:父组件用单个
useRef存储多个子组件的引用,最后只会保留最后一个子组件的ref,滚动时无法关闭所有打开的菜单。
修复方案
1. 修正父组件的Ref管理与滚动回调
把单个ref改成数组ref存储所有子组件的关闭函数,同时在滚动时遍历执行所有关闭操作:
import { useRef } from 'react' import SidebarMenuElement from '@/Layouts/Authenticated/Partials/Sidebar/MenuElement' // 示例导航数据,根据实际场景替换 const navigation = [ { name: '菜单1', url: '/menu1', icon: () => <span>📁</span> }, { name: '菜单2', url: '/menu2', icon: () => <span>📂</span> }, ] export default function Sidebar() { const sidebarMenuElementRefs = useRef([]) const handleScroll = () => { // 遍历所有子组件的关闭函数并执行 sidebarMenuElementRefs.current.forEach(closeFn => { typeof closeFn === 'function' && closeFn() }) } return ( <> <div> <div className="h-full w-[inherit] overflow-y-auto scroll-smooth" style={{ scrollbarGutter: 'stable both-edges' }} onScroll={handleScroll} > <nav> <div> <ul> {navigation.map((item, i) => ( <li key={item.name}> <SidebarMenuElement data={item} ref={el => sidebarMenuElementRefs.current[i] = el} /> </li> ))} </ul> </div> </nav> </div> </div> </> ) }
2. 修正子组件的Ref逻辑
直接在Menu的回调中把close函数存入ref,无需通过MenuButton的ref传递:
import { useRef, forwardRef, useImperativeHandle } from 'react' import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/react' import { Link } from '@inertiajs/react' const SidebarMenuElement = forwardRef(function SidebarMenuElement(props, ref) { const { data } = props const closeMenuRef = useRef(null) // 向父组件暴露关闭函数 useImperativeHandle(ref, () => () => closeMenuRef.current?.(), []) return ( <Menu> {({ close }) => { // 实时更新close函数引用 closeMenuRef.current = close return ( <> <MenuButton className="flex items-center gap-2 p-2"> <span>{data.icon()}</span> <span>{data.name}</span> </MenuButton> <MenuItems className="absolute bg-white shadow-md rounded-md p-2"> <MenuItem> <Link href={data.url} className="block px-4 py-2 hover:bg-gray-100"> {data.name} </Link> </MenuItem> </MenuItems> </> ) }} </Menu> ) }) export default SidebarMenuElement
内容的提问来源于stack exchange,提问作者ToxifiedM
相关产品推荐
相关产品推荐

