You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React HOC技术问题:如何在子组件中访问父传入的closePopover方法?

问题:子组件无法访问Popover高阶组件传递的closePopover方法

我编写了一个Popover高阶组件(HOC),已将closePopover方法作为props传递,但不知如何在子组件中访问该方法。相关代码如下:

自定义Popover组件代码

import { useState, useCallback, cloneElement } from 'react'
import { EuiButtonEmpty, EuiPopover } from '@elastic/eui'

const CustomPopover = ({ children }) => {
  const [isPopoverOpen, setIsPopoverOpen] = useState(false)

  const closePopover = useCallback(() => setIsPopoverOpen(false), [])
  const onButtonClick = () => setIsPopoverOpen(isPopoverOpen => !isPopoverOpen)

  const button = (
    <EuiButtonEmpty
      iconType='boxesHorizontal'
      iconSide='right'
      onClick={onButtonClick}
    ></EuiButtonEmpty>
  )

  return (
    <div>
      <EuiPopover
        button={button}
        isOpen={isPopoverOpen}
        closePopover={closePopover}
      >
        {cloneElement(children, { closePopover })}
      </EuiPopover>
    </div>
  )
}

export default CustomPopover

组件使用代码

<CustomPopover>
  <div className='flex flex-col space-y-5'>
    <button
      onClick={() => setSortAsc(true)}
      className='hover:bg-slate-100'
    >
      Sort by Oldest Message
    </button>
    <button
      onClick={() => setSortAsc(false)}
      className='hover:bg-slate-100'
    >
      Sort by Latest Message
    </button>
  </div>
</CustomPopover>

解决方案

你当前的问题在于:cloneElement(children, { closePopover }) 是给外层的原生div元素添加了closePopover属性,但原生DOM元素不会处理React props,内部的按钮自然无法拿到这个方法。下面提供两种可行的修改方式:

方式一:将内容封装为自定义组件

把Popover里的内容抽成一个接收closePopover的React组件,这样就能直接在组件内调用该方法:

// 封装内容组件
const PopoverContent = ({ closePopover, setSortAsc }) => {
  return (
    <div className='flex flex-col space-y-5'>
      <button
        onClick={() => {
          setSortAsc(true);
          closePopover(); // 调用关闭方法
        }}
        className='hover:bg-slate-100'
      >
        Sort by Oldest Message
      </button>
      <button
        onClick={() => {
          setSortAsc(false);
          closePopover(); // 调用关闭方法
        }}
        className='hover:bg-slate-100'
      >
        Sort by Latest Message
      </button>
    </div>
  )
}

// 修改后的使用方式
<CustomPopover>
  <PopoverContent setSortAsc={setSortAsc} />
</CustomPopover>

方式二:使用函数式Children(更灵活)

修改CustomPopover组件,让它支持接收函数类型的children,直接把closePopover传递给函数:

// 修改CustomPopover组件
import { useState, useCallback, cloneElement } from 'react'
import { EuiButtonEmpty, EuiPopover } from '@elastic/eui'

const CustomPopover = ({ children }) => {
  const [isPopoverOpen, setIsPopoverOpen] = useState(false)

  const closePopover = useCallback(() => setIsPopoverOpen(false), [])
  const onButtonClick = () => setIsPopoverOpen(isPopoverOpen => !isPopoverOpen)

  const button = (
    <EuiButtonEmpty
      iconType='boxesHorizontal'
      iconSide='right'
      onClick={onButtonClick}
    ></EuiButtonEmpty>
  )

  return (
    <div>
      <EuiPopover
        button={button}
        isOpen={isPopoverOpen}
        closePopover={closePopover}
      >
        {/* 判断children是否为函数,是的话传递closePopover */}
        {typeof children === 'function' ? children({ closePopover }) : children}
      </EuiPopover>
    </div>
  )
}

export default CustomPopover

然后使用时直接通过函数参数拿到closePopover:

<CustomPopover>
  {({ closePopover }) => (
    <div className='flex flex-col space-y-5'>
      <button
        onClick={() => {
          setSortAsc(true);
          closePopover();
        }}
        className='hover:bg-slate-100'
      >
        Sort by Oldest Message
      </button>
      <button
        onClick={() => {
          setSortAsc(false);
          closePopover();
        }}
        className='hover:bg-slate-100'
      >
        Sort by Latest Message
      </button>
    </div>
  )}
</CustomPopover>

内容的提问来源于stack exchange,提问作者Arpit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 11:20:38