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
相关产品推荐
相关产品推荐

