2017-01-19 14 views
3

ラップされたコンポーネントの外にあるクリックをリッスンするためにHOCを作成しました。Reactjs - 高次コンポーネントのアンマウントが正しく機能しない

HOCは、次のようになります。

const addOutsideClickListener = (WrappedComponent) => { 

    class wrapperComponent extends React.Component { 

     componentDidMount() { 
      console.log('*** component did MOUNT called ***'); 
      document.addEventListener('click', this._handleClickOutside.bind(this), true); 
     } 

     componentWillUnmount() { 
      console.log('*** component will UNMOUNT called ***'); 
      document.removeEventListener('click', this._handleClickOutside.bind(this), true); 
     } 

     _handleClickOutside(e) { 
      const domNode = ReactDOM.findDOMNode(this); 

      if ((!domNode || !domNode.contains(e.target))) { 

       this.wrapped.handleClickOutside(); 
      } 
     } 

     render() { 

      return (
       <WrappedComponent 
        ref={(wrapped) => { this.wrapped = wrapped }} 
        {...this.props} 
       /> 
      ); 
     } 
    } 

    return wrapperComponent; 
} 

それは...ほとんどの時間を正常に動作します。

包まれたコンポーネントがアンマウントされる場合には、メソッド「componentWillUnmount」は呼び出されるが、「にremoveEventListenerは」イベントをリッスンし続け、私はエラーメッセージが 得る「不明なエラー:。findDOMNodeをアンマウントコンポーネントで呼び出されました」

何が原因なのでしょうか?

+0

は、この参照してください。あなたは、 "バインド" を使用する場合https://gist.github.com/Restuta/e400a555ba24daa396ccを新しい関数の参照は、技術的には異なる関数を削除しようとしています – Jayce444

+0

ありがとう!この変更は新しい問題を生み出します - 私は今どこでもクリックするたびにこのエラーを受け取ります。 "キャッチされていないエラー:要素はReactComponentでもDOMNodeでもないようです" – Petrov

+0

ここで正しい答えが得られるように新しい質問を投稿しました。 http://stackoverflow.com/questions/41740360/reactjs-higher-order-component-unmount-not-working-correctly-part-2を参照してください – Petrov

答えて

1

コンストラクタにこれを追加

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

     componentWillUnmount() { 
      document.removeEventListener('click', this._handleClickOutside, true); 
     } 
+0

しかし、このソリューションは現在、エラーをスローします。b/c document.addEventListenerはコールバックを 'document'にバインドします... – Petrov

+0

エラーは何ですか?実際には別のエラーです。コードでは、追加した関数にイベントリスナーを削除していませんでした。新しい関数を作成していましたが、ここにコンソールのエラーは何文字入力できますか? – challenger

+0

問題は、document.addEventListenerがthis._handleClickOutsideのコールバックを 'document'に自動的にバインドすることです。したがって、コンストラクタ内のコンポーネントにコールバック内でバインドしても、const domNode = ReactDOM.findDOMNode(this);最終的に '文書'で呼び出される...これはよく知られている混乱のようです:https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#The_value_of_this_within_the_handler – Petrov

3

removeEventListenerが機能しない理由は、の新しく作成された機能を削除しようとしているためです。 addEventListenerも同様です。これらは2つの完全に異なる機能であり、お互いの参照はまったくありません。

あなたのメソッド_handleClickOutsideをバインドする必要があります。そのため、Reactは正確に1つのバージョンを知っています。あなたはES6の矢印の方法論と

constructor() { 
    super(); 
    this._handleClickOutside.bind(this); 
} 

または自動それバインドとコンストラクタに

_handleClickOutside = (e) => { ... } 

それを結合することによって、今、あなたは

document.addEventListener('click', this._handleClickOutside, true); 

であなたのイベントリスナーにバインドさメソッドを渡すことを行うと、リスナーを削除します。

this._handleClickOutside = this._handleClickOutside.bind(this) 

をしてから、この操作を行います:

+0

OKはあなたの提案を試みました。今度は「Uncaught Error:Elementは表示されません。 ReactComponentもDOMNodeも "をクリックしてください。 – Petrov

+0

これは私が考える新しい疑問ですので、ここに入れてください: – Petrov

+0

ここhttp://stackoverflow.com/questions/41740360/reactjs-higher-order-component-unmount-not-working-correctly-part-2 – Petrov

関連する問題