Javascript React forwardRef HoC不提供对容器元素的引用

Javascript React forwardRef HoC不提供对容器元素的引用,javascript,reactjs,higher-order-components,Javascript,Reactjs,Higher Order Components,我正在尝试为一个关闭元素在其空间外单击构建一个通用的HOC(通用的外部关闭解决方案) 在我看来,这可以通过forwardRef和HOC实现,尽管在官方文档中有一个例子,但我似乎无法正确实现 因此,我希望我的HOC创建对组件容器的引用。它是包装的,因为它有处理程序来跟踪点击并对其进行操作。例如,假设我们有一个通用的下拉组件,人们会期望我可以在该组件区域之外的任何单击上关闭它 我目前拥有的代码: import React from 'react'; function withClose(Compo

我正在尝试为一个关闭元素在其空间外单击构建一个通用的HOC(通用的外部关闭解决方案)

在我看来,这可以通过forwardRef和HOC实现,尽管在官方文档中有一个例子,但我似乎无法正确实现

因此,我希望我的HOC创建对组件容器的引用。它是包装的,因为它有处理程序来跟踪点击并对其进行操作。例如,假设我们有一个通用的下拉组件,人们会期望我可以在该组件区域之外的任何单击上关闭它

我目前拥有的代码:

import React from 'react';

function withClose(Component) {
 class ClickContainer extends React.Component {
    constructor() {
      super();
      this.handleClose = this.handleClose.bind(this);
    }

    componentDidMount() {
      document.addEventListener('click', this.handleClose);
    }

    componentWillUnmount() {
      document.removeEventListener('click', this.handleClose);
    }

    handleClose(e) {
      // I expect having here context of container of wrapped component to do something like
      const { forwardedRef } = this.props; // <- I expect having context in forwardedRef variable
    }

    render() {
      const { forwardedRef, ...rest } = this.props;
      return <Component ref={forwardedRef} {...rest} />;
    }
  }

  return React.forwardRef((props, ref) => {
    return <ClickContainer {...props} forwardedRef={ref} />;
  });
}

export default withClose;
从“React”导入React;
带关闭的函数(组件){
类ClickContainer.Component{
构造函数(){
超级();
this.handleClose=this.handleClose.bind(this);
}
componentDidMount(){
document.addEventListener('click',this.handleClose);
}
组件将卸载(){
document.removeEventListener('click',this.handleClose);
}
手环(e){
//在这里,我希望包装组件的容器上下文可以做如下事情
const{forwardedRef}=this.props;//{
返回;
});
}
用close导出默认值;
我在这里遗漏了什么?我不能让它工作,我只得到包装组件的上下文,而不是元素本身


非常感谢!几天前我实现了同样的功能。 我想要一个处理
onClickoutside

我希望该组件在每次单击时检查子对象是否单击,以及是否调用子对象上的函数

这就是我的解决方案:

import React from 'react';

export default function withClickOutside(WrappedComponent) {
  class WithClickOutside extends WrappedComponent {
    constructor(props) {
      super(props);
      this.handleClickOutside = this.handleClickOutside.bind(this);
      this.wrappedElement = React.createRef();
    }

    componentDidMount() {
      document.addEventListener('click', this.handleClickOutside, true);
    }

    componentWillUnmount() {
      document.removeEventListener('click', this.handleClickOutside, true);
    }


    handleClickOutside(event) {
       if (event.type !== 'click') return;
       if (!this.wrappedElement.current) {
          throw new Error(`No ref for element ${WrappedComponent.name}. Please create ref when using withClickOutside`);
        }

      if (!this.wrappedElement.current.contains(event.target)) {
         if (!this.onClickOutside) {
           throw new Error(`${WrappedComponent.name} does not implement onClickOutside function. Please create onClickOutside function when using withClickOutside`);
         }

       this.onClickOutside(event);
     }
   }


   render() {
     const wrapped = super.render();
     const element = React.cloneElement(
       wrapped,
       { ref: this.wrappedElement },
     );

     return element;
   }
 }

 return WithClickOutside;
}

然后,您包装的组件必须实现一个名为
onClickOutside

Ref的函数,并将其传递给元素

结帐

假定

export const Popup = (props,) => {
  const { name, forwardRef } = props;
  return (
   <div ref={forwardRef}>  // You need to pass it down from props
     {name}
   </div>
  )
}
export const Popup=(道具,)=>{
const{name,forwardRef}=props;
返回(
//你需要把它从道具上传下来
{name}
)
}
以及特别组织

export function withClose(Component) {
  class ClickContainer extends React.Component {
    constructor() {
     super();
     this.handleClose = this.handleClose.bind(this);
    }

    componentDidMount() {
      document.addEventListener('click', this.handleClose);
    }

    componentWillUnmount() {
      document.removeEventListener('click', this.handleClose);
    }

    handleClose(e) { 
     const { forwardRef } = this.props;
     console.log(forwardRef);
    }

    render() {
      const { forwardRef, ...rest } = this.props;
      return <Component forwardRef={forwardRef} {...rest} />;
    }
  }

  return React.forwardRef((props, ref) => {
    return <ClickContainer {...props} forwardRef={ref} />;
  });
}
带关闭的导出功能(组件){
类ClickContainer.Component{
构造函数(){
超级();
this.handleClose=this.handleClose.bind(this);
}
componentDidMount(){
document.addEventListener('click',this.handleClose);
}
组件将卸载(){
document.removeEventListener('click',this.handleClose);
}
handleClose(e){
const{forwardRef}=this.props;
控制台日志(forwardRef);
}
render(){
const{forwardRef,…rest}=this.props;
返回;
}
}
return React.forwardRef((道具,ref)=>{
返回;
});
}
期待

 const CloseablePopup = withClose(Popup);

  class App extends Component {
    popupRef = React.createRef();
    render() {
      return (<CloseablePopup ref={popupRef} name="Closable Popup" />);
    }
  }
const CloseablePopup=withClose(Popup);
类应用程序扩展组件{
popupRef=React.createRef();
render(){
返回();
}
}

什么是
this.containerRef
?您需要将
this.props.forwardedRef
传递给element@Orar是的,很抱歉,这只是我尝试过的遗留问题,我将其更改为正确的代码…基本上这是正确的解决方案,我缺少在容器中创建ref…虽然这并不能完全回答我的问题。你认为呢知道有没有可能在不提供父级引用的情况下实现它?这要求我在多个位置定义引用,而不是让它自己处理所有事情。ThanksHOC在不由包装组件处理的情况下传递ref可能会导致错误,如果包装组件是函数。如果包装组件是类,ref只能访问类的实例,而不能访问容器元素。阅读这里,这是一个解决方案,它可以工作,但有点粗糙。如果可能的话,我想在没有cloneElement的情况下实现它。你能想到其他实现方案吗?我知道它的abit hack,但出于某种原因采用了这个解决方案n尝试在没有克隆元素的情况下使其工作,并获得对已包装组件的引用,但没有工作。好的是,您不需要在已包装组件中处理引用,因此保存了一些代码和错误,而忘记了添加它们