如何在反应中重新绑定点击事件

时间:2017-05-31 18:19:42

标签: javascript reactjs

在react中动态更改事件绑定的建议/最干净的方法是什么?

例如,如果我最初有这样的按钮

<button type="button" onClick={this.handleFirstClick}>

然后在handleFirstClick方法

handleFirstClick() {
    //do other stuff
    //rebind the button, so that next time it's clicked, handleSecondClick() would be called
}

如果不清楚我的意思,这就是我想要做的事情,使用jQuery而不是React

$('#myButton').on('click', handleFirstClick);

function handleFirstClick() {
    //other stuff
    $('#myButton').off('click');
    $('#myButton').on('click', handleSecondClick);
}

5 个答案:

答案 0 :(得分:1)

解决方案1:反应状态和Ternary Expressions

为了更改事件的绑定,您需要在render方法中使用if-else。为组件创建一些状态以处理是否已单击该按钮。第一次单击后,设置状态,以便将来运行第二个函数。您可以添加基本ternary expression来检查render()中的状态。

&#13;
&#13;
class FancyButton extends React.Component {
  constructor() {
    super()
    this.state = {
      clicked: false
    }

    //Bindings for use in render()
    this.onFirstClick = this.onFirstClick.bind(this)
    this.onSecondClick = this.onSecondClick.bind(this)
  }

  onFirstClick() {
    console.log("First click")
    this.setState({
      clicked: true
    })
  }

  onSecondClick() {
    console.log("Another click")
  }

  render() {
    return ( <
      button onClick = {
        this.state.clicked ? this.onSecondClick : this.onFirstClick
      } > Click < /button>
    )
  }
}

ReactDOM.render( < FancyButton / > , document.getElementById("root"))
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
&#13;
&#13;
&#13;

解决方案2:在对象属性中保持状态

从更一般的意义上讲,您可能不需要在render方法中更改事件处理程序。如果只调用一个onClick处理程序并切换一个对象属性,则可以在每次单击后跳过重新呈现react组件(由于跳过对this.setState的调用)。

&#13;
&#13;
class FancyButton extends React.Component {
  constructor() {
    super()
    this.clicked = false

    //Bindings for use in render()
    this.onClick = this.onClick.bind(this)
  }

  onClick() {
    if (!this.clicked) {
      this.onFirstClick()
    } else {
      this.onSecondClick()
    }
    this.clicked = true
  }

  onFirstClick() {
    console.log("First click")
  }

  onSecondClick() {
    console.log("Another click")
  }

  render() {
    return ( <
      button onClick = {
        this.onClick
      } > Click < /button>
    )
  }
}

ReactDOM.render( < FancyButton / > , document.getElementById("root"))
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
&#13;
&#13;
&#13;

我个人会推荐第二种解决方案,因为它效率更高,但您可以根据自己的情况决定最适合自己的情况。

答案 1 :(得分:1)

只需保留一个计数器,单击按钮的次数,然后使用它来分配处理程序。请参阅此片段

&#13;
&#13;
class App extends React.Component{
	constructor(props){
		super(props)
		this.state={
			clicked: 0
		}
	}
	firstClick(){
		console.log("first click")
		this.setState({clicked: 1})
	}
	afterClick(){
		console.log("more clicks")
	}

	render(){
		return(
			<div><button onClick={this.state.clicked === 0 ? this.firstClick.bind(this) : this.afterClick.bind(this)}>Click me</button>
			</div>
		)
	}
}

ReactDOM.render(<App />, document.getElementById("app"))
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
&#13;
&#13;
&#13;

答案 2 :(得分:1)

你可以使用一个闭包。

const createClickHandler = () => {
  const firstClickHandler = () => {}
  const secondClickHandler = () => {}
  let clicked = false

  return () => {
    if (clicked) return secondClickHandler()
    clicked = true
    firstClickHandler()
  }
 } 

答案 3 :(得分:0)

创建一个监视状态并确定应该运行哪个函数的函数。

handleClick() {
    if (this.state.clickNumber === 1) {
        this.handleFirstClick()
    } elseif (this.state.clickNumber === 2) {
        this.handleSecondClick()
    }
}
handleFirstClick() {
    //do stuff
    this.setState({clickNumber: 2})
}
handleSecondClick(){
    //do other stuff

    // maybe increment click number again this.setState({clickNumber: 3})
}

答案 4 :(得分:0)

在React中,您最好使用state来管理这些事件。您可以在单个按钮组件中或在呈现按钮组件的父组件中保存状态和操作。

在设置此项时,按钮组件使用二进制状态,该状态使用布尔值在单击一个和两个函数之间切换。这也可以很容易地改为功能二并通过修改按钮的handleClick setState调用,或者继续迭代到其他功能 - 或者甚至在每次点击时使用更新的输入调用相同的功能(取决于你的用例)。

在这个例子中,我决定在一个精简的React App中展示它是如何工作的。在这个例子中,你会注意到我保持每个按钮的状态。令人怀疑的是另一个组件需要跟踪点击次数,因此这遵循将状态下推到最低可能组件的反应原则。在这种情况下,我允许父组件保存将作用于按钮状态的函数。我没有看到这些函数的必要性,并且它们的开销也与每个按钮组件重复,但按钮组件当然也可以自己调用函数。

我添加了两个按钮来显示他们将如何单独维护他们的状态。原谅注释块格式,它在片段窗口之外不能很好地显示。

&#13;
&#13;
/**
	*		@desc Sub-component that renders a button
	*		@returns {HTML} Button
	*/
class BoundButton extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);

    this.state = ({
      //toggled in this example to keep click state
      click2: false,
    });
  }
  
  handleClick(e) {
    //calls parent method with the clicked button element and click state
    this.props.click(e.nativeEvent.toElement, this.state.click2);
    
    //toggles click state
    this.setState({ click2: !this.state.click2 });
  }

  render() {
    
    return (
      <button 
        id = {this.props.id}
        name = {this.props.name}
        className = {this.props.className}
        onClick = {this.handleClick}  >
        Click Here {this.state.click2 ? '2' : '1'}!
      </button>        
    );
  }
  
}



/**
	*		@desc Component that creates and binds button sub-components
	*		@returns {HTML} Bound buttons
	*/
class BindExample extends React.Component {
  constructor(props) {
    super(props);
    this.handleButtonClick = this.handleButtonClick.bind(this);
    this.clickAction1 = this.clickAction1.bind(this);
    this.clickAction2 = this.clickAction2.bind(this);

    this.state = ({
      //state vars
    });
  }
  
  clickAction1(el) {
    console.log('Action 1 on el: ', el);
  }
  
  clickAction2(el) {
    console.log('Action 2 on el: ', el);
  }
  
  handleButtonClick(el, click2) {

    console.log('click!');
    
    if (click2) this.clickAction2(el);
    else this.clickAction1(el);
  }
  
  render() {
    
    return (
      <div>
        <BoundButton 
          id='ex-btn1' 
          name='bound-button-1'
          className='bound-button'
          click={this.handleButtonClick} />
        <BoundButton 
          id='ex-btn2' 
          name='bound-button-2'
          className='bound-button'
          click={this.handleButtonClick} />
      </div>
    );
  }
  
}

/**
	*		@desc React Class renders full page. Would have more components in a
  *     real app.
	*		@returns {HTML} full app
	*/
class App extends React.Component {
  render() {
    return (
      <div className='pg'>
        <BindExample  />
      </div>
    );
  }
}


/**
	*		Render App to DOM
	*/

/**
	*		@desc ReactDOM renders app to HTML root node
	*		@returns {DOM} full page
	*/
ReactDOM.render(
  <App/>, document.getElementById('root')
);
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="root">
  <!-- This div's content will be managed by React. -->
</div>
&#13;
&#13;
&#13;