2017-05-04 41 views
0

我希望使高階組件管理外部點擊。當確定用戶在給定組件外單擊時,應該執行某個傳遞的功能。此HOC需要兩個參數:反應HOC處理給定組件外的點擊

  • BoundaryComponent:我們感興趣的是確定是否點擊是它
  • onOutsideClick外側的部件:當點擊發生時在組件外的函數來執行

ClickOutside組件的樣子:

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() 
      } 
     } 
    } 
} 

,我試圖利用這個組件是這樣的:

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) 

以上實現將按我希望......

但是,在定義onOutsideClick的DropdownPickList類的範圍之外,然後覆蓋這個類的構造函數中的這個變量引用只是感覺不對。但它似乎是獲得關閉下拉式課程所需的道具和狀態的唯一途徑。

我也嘗試在DropdownPickList類中使用靜態方法來處理onOutsideClick,但與此問題是這個類作爲一個未呈現的組件傳遞,所以我沒有訪問它的handleClick中的任何實例方法的HOC。

必須有更好的方法來做到這一點?任何幫助或替代實施的想法/模式將不勝感激!

回答

1

而不是創造一個功能,只是出口包裝和變化如下:

  • BoundaryComponent:此舉是包裝的兒童(所以這將是真正的包裝),像這樣:

    <Wrapper> 
        <BoundaryComponent /> 
    <Wrapper> 
    

雖然裏面的包裝,你會呈現{} this.props.children

  • onOutsideClick:在onOutsideClick功能移動到道具Wrapper

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