代码之家  ›  专栏  ›  技术社区  ›  Mario Nikolaus

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

  •  3
  • Mario Nikolaus  · 技术社区  · 7 年前

    在我看来,这可以通过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;
    

    我错过了什么?我不能让它工作,我只得到包装组件的上下文,而不是元素本身。

    非常感谢!

    2 回复  |  直到 7 年前
        1
  •  3
  •   Orar    7 年前

    Ref应该传递给元素

    https://codesandbox.io/s/7yzoqm747x

    假设

    export const Popup = (props,) => {
      const { name, forwardRef } = props;
      return (
       <div ref={forwardRef}>  // You need to pass it down from props
         {name}
       </div>
      )
    }
    

    以及特别组织

    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} />;
      });
    }
    

     const CloseablePopup = withClose(Popup);
    
      class App extends Component {
        popupRef = React.createRef();
        render() {
          return (<CloseablePopup ref={popupRef} name="Closable Popup" />);
        }
      }
    
        2
  •  1
  •   tubu13    7 年前

    几天前我实现了同样的事情。 我想要一个把手 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 .