Реагировать на forwardRef HoC без ссылки на элемент контейнера - PullRequest
0 голосов
/ 19 декабря 2018

Я пытаюсь создать универсальный HOC для закрывающего элемента при щелчке за пределами его пространства (универсальное закрытие при внешнем решении).

На мой взгляд, этого можно добиться с помощью реализации forwardRef и HOC ихотя в официальных документах есть пример, я не могу понять его правильно.

Поэтому я хочу, чтобы мой HOC создал ссылку на контейнер компонента.Это обертка, потому что она имеет обработчики для отслеживания кликов и воздействия на них.Например, допустим, у нас есть общий компонент Dropdown, можно было бы ожидать, что я могу закрыть его при любом щелчке за пределами области этого компонента.

Код, который у меня сейчас есть:

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 ]

0 голосов
/ 19 декабря 2018

Ссылка должна быть передана до элемента

Оформить заказ 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>
  )
}

И HOC

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" />);
    }
  }
0 голосов
/ 19 декабря 2018

Я реализовал то же самое несколько дней назад.Я хотел, чтобы HOC обрабатывал onClickoutside

. Я хотел, чтобы этот компонент проверял при каждом щелчке, был ли дочерний элемент щелчком мыши или нет, и выполнял ли он для вызова функции для дочернего элемента.

thisбыло мое решение:

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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...