2017-05-04 2 views
0

Ich möchte eine Higher Order Component erstellen, um externe Klicks zu verwalten. Wenn festgestellt wird, dass ein Benutzer außerhalb einer bestimmten Komponente geklickt hat, sollte eine bestimmte übergebene Funktion ausgeführt werden. Diese HOC dauert 2 Parameter:Reactive HOC, um Klicks außerhalb einer bestimmten Komponente zu behandeln

  • BoundaryComponent: die Komponente wir bei der Bestimmung interessiert sind, wenn Klicks außerhalb davon
  • onOutsideClick sind: eine Funktion auszuführen, wenn ein Klick außerhalb der Komponente auftritt

Diese ClickOutside Komponente wie folgt aussieht:

import React from 'react' 
const { Component } = React 
import { findDOMNode } from 'react-dom' 

export default function ClickOutside (BoundaryComponent, onOutsideClick) { 
    return class Wrapper extends Component { 
     constructor (props) { 
      super(props) 
     } 

     componentDidMount() { 
      document.addEventListener('click', this.handleClick.bind(this), true) 
     } 

     componentWillUnmount() { 
      document.removeEventListener('click', this.handleClick.bind(this), true) 
     } 

     render() { 
      const props = Object.assign({}, this.props, { ref: this.getContainer.bind(this) }) 
      return (
       <BoundaryComponent 
        {...props} 
       /> 
      ) 
     } 

     getContainer (wrapped) { 
      this.container = findDOMNode(wrapped) 
     } 

     handleClick(e) { 
      if (this.container && !this.container.contains(e.target) && typeof onOutsideClick === 'function') { 
       onOutsideClick() 
      } 
     } 
    } 
} 

Und ich versuche, diese Komponente wie folgt zu verwenden:

import React from 'react' 
const { ClickOutside } = 'utils/click-outside' 
import { updatePicklistActiveIndex } from 'components/store/actions' 
import { getPicklistActiveIndex } from 'components/store/selectors' 
import PickList from 'components/picklist' 

// ... 

function mapDispatchToProps (dispatch) { 
    return { 
     updatePicklistActiveIndex: (activeIndex) => { dispatch(updatePicklistActiveIndex(activeIndex)) }, 
    } 
} 

function mapStateToProps (state) { 
    return { 
     picklistActiveIndex: getPicklistActiveIndex(state), 
    } 
} 

let onOutsideClick = null // This feels like a code smell 

class DropdownPickList extends PickList { 
    constructor(props) { 
     super(props) 
     this.state = { 
      dropdownVisible: false, 
     } 
     onOutsideClick =() => { 
      this.props.updatePicklistActiveIndex(-1) 
      this.setState({ dropdownVisible: false }) 
     } 
    } 

    // ... 

    render() { 
     return (
      //...jsx to render DropdownPickList 
     ) 
    } 
} 
const pickList = ClickOutside(DropdownPickList,() => { onOutsideClick() }) 
export default connect(mapStateToProps, mapDispatchToProps)(pickList) 

Die obige Umsetzung funktioniert, wie ich erwarten würde ...

Aber die Definition onOutsideClick außerhalb des Kontextes der DropdownPickList Klasse, und dann überschreiben Diese Variablenreferenz innerhalb des Konstruktors dieser Klasse fühlt sich einfach falsch an. Aber es scheint die einzige Möglichkeit zu sein, Zugriff auf die Requisiten und den Zustand innerhalb der Klasse zu erhalten, die benötigt werden, um das Dropdown zu schließen.

Ich habe auch versucht, eine statische Methode in der DropDownPickList-Klasse zu verwenden, um das OnOutsideClick zu behandeln, aber das Problem dabei ist, dass Klasse als eine nicht gerenderte Komponente übergeben wird, so habe ich keinen Zugriff auf eine der Instanzmethoden in meinem handleClick von der HOC.

Es muss einen besseren Weg geben, dies zu tun? Jede Hilfe oder alternative Implementierung Ideen/Muster würde sehr geschätzt werden!

Antwort

1

Anstatt eine Funktion zu erstellen, exportieren nur die Hülle und ändern wie die folgenden:

  • BoundaryComponent: bewegen die Kinder der Hülle sein (so wird es tatsächlich ein Wrapper sein) wie folgt:

    <Wrapper> 
        <BoundaryComponent /> 
    <Wrapper> 
    

Während die Innenseite der Folie werden Sie machen {this.props.children}

  • onOutsideClick: die onOutsideClick Funktion Verschieben an den Stützen von Wrapper:

    <Wrapper onOutsideClick={this.onOutsideClick}> 
        <BoundaryComponent /> 
    <Wrapper> 
    
Verwandte Themen