2017-10-11 14 views
1

setStateを呼び出した後にイベントリスナーを追加すると、そのイベントを再度トリガーするとイベントリスナーが呼び出されるだけです。しかし、下の例から、divをクリックすると、状態が変更された後にイベントリスナーが呼び出されます。setStateの後でaddEventListenerを呼び出すと、イベントが2回実行されるようです

私はtoggleOpenevt.stopPropagation()を呼び出す場合、私はaddEventListenerを削除するかどうかは発生しませんが、thte状態が変更された後、私はそれを設定していた場合にイベントリスナーが呼び出さなっている理由私は思ったんだけど。

setStateは状態を非同期に変更しません。これは、イベントが伝播した後にコールバックが呼び出されることを意味しますか?

import React from 'react'; 
import classNames from 'classnames'; 

import css from './Dropdown.scss'; 


export class Dropdown extends React.Component { 
    constructor(props) { 
    super(props); 

    this.state = { 
     open: false, 
    } 
    } 

    toggleOpen = (evt) => { 
    window.removeEventListener('click', this.toggleOpen); 

    this.setState({ 
     open: !this.state.open, 
    },() => { 
     window.addEventListener('click', this.toggleOpen); 
    }); 
    } 

    render() { 
    const dropdownContentClasses = classNames(css.dropdownContent, { 
     [css.dropdownContent_open]: this.state.open, 
    }); 

    console.log(this.state.open) 

    return (
     <div className={css.dropdownContainer}> 
     <div onClick={this.toggleOpen}> 
      {this.props.title} 
     </div> 
     <div className={dropdownContentClasses}> 
      {this.props.children} 
     </div> 
     </div> 
    ) 
    } 
} 

答えて

1

2もの。まず、https://reactjs.org/docs/react-component.html#setstateからあなたの新しい状態を計算するprevStateプロパティを使用したい:

toggleOpen = evt => { 
    this.setState((prevState, props) => { 
    return { open : ! prevState.open }; 
    }); 
} 

第二に、それはcomponentDidMount()フェーズ中にイベントハンドラを追加し、componentWillUnmount()相の間にそれを削除すると良いでしょう:

componentDidMount() { 
    window.addEventListener('click', this.toggleOpen); 
} 
componentWillUnmount() { 
    window.removeEventListener('click', this.toggleOpen); 
} 
+0

私は私の質問に答えるとは思わない。 'prevState'を使うようにsetStateを変更しても問題は解決されません。リスナーを 'componentWillMount'に移動すると、ウィンドウ上の任意のクリックに対してドロップダウンが開きます。私の質問は、状態の更新とイベントの伝播の後にイベントリスナーが追加されても、状態を設定するのと同じクリックでイベントリスナーが呼び出される理由です。 – gzzo

0

toggleOpenでウィンドウイベントを追加する代わりに、state.openチェックでcomponentDidMountの内部にイベントを追加することをお勧めします。 https://jsfiddle.net/69z2wepo/87489/

1

それが伝播が窓に到達した時点で、リスナーが追加されたように思えるし、その後のEventListenerを呼び出す:

componentDidMount() { 
    window.addEventListener('click', (e) => { 
     this.state.open && this.toggleOpen(e); 
    }); 
} 

は、私がここにフィドルを追加しました。 event.stopPropagationを追加するとそれを解決するはずです。

関連する問題