2017-05-31 75 views
2

在反应中动态更改事件绑定的建议/最干净的方式是什么?如何在反应中重新绑定点击事件

例如,如果我最初在handleFirstClick方法

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

有这样

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

一个按钮,然后在情况下,它不是完全清楚我的意思,这里就是想什么我使用jQuery代替React

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

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

我不知道这是否是正确的方法,但我会对那个按钮计算点击次数的状态,并且有'handleClick()'相应地调用合适的功能。 –

回答

1

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

为了改变事件的绑定,你需要在render方法中有一个if-else。为组件创建一些状态以处理按钮是否已被点击。第一次点击后,设置状态,以便将来运行第二个功能。您可以包含基本的ternary expression以检查render()中的状态。

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"))
<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>

解决方法2:在一个对象的属性

坚持国家在更一般的意义上,你可能不需要改变事件处理程序在你的渲染方法。如果您只调用一个onClick处理程序并切换对象属性,则可以在每次点击后跳过重新渲染反应组件(由于跳过this.setState)。

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"))
<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>

我个人建议的第二个解决方案,因为它是更有效的,但你可以在你自己的哪个适合您的情况最好的决定。

+0

尽管这并不能完全回答这个问题,但我认为它是被接受的,因为它很干净而且有效。这很可能是我的问题的答案是,“这不是你在做什么反应” – Jedediah

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

只需按住点击按钮的次数,然后使用它来指定处理程序。看到这个片段,

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

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

 
ReactDOM.render(<App />, document.getElementById("app"))
<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>

1

你可以使用一个闭合。

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

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

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

在设置这个按钮组件时,利用了一个二进制状态,用一个布尔值来点击一个和两个函数。这也可以通过修改按钮的handleClick或者继续迭代到附加函数 - 或者甚至每次点击更新输入(取决于您的用例)调用相同的函数,从而轻松更改为函数two并保持在那里。

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

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

/** 
 
\t * \t \t @desc Sub-component that renders a button 
 
\t * \t \t @returns {HTML} Button 
 
\t */ 
 
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>   
 
    ); 
 
    } 
 
    
 
} 
 

 

 

 
/** 
 
\t * \t \t @desc Component that creates and binds button sub-components 
 
\t * \t \t @returns {HTML} Bound buttons 
 
\t */ 
 
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> 
 
    ); 
 
    } 
 
    
 
} 
 

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

 

 
/** 
 
\t * \t \t Render App to DOM 
 
\t */ 
 

 
/** 
 
\t * \t \t @desc ReactDOM renders app to HTML root node 
 
\t * \t \t @returns {DOM} full page 
 
\t */ 
 
ReactDOM.render(
 
    <App/>, document.getElementById('root') 
 
);
<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>

+0

我想知道为什么有人会投我的答案,我刚刚花了一个小时写一个原始解决方案,当你跑步?我认为这是一个坚实的答案,而没有评论的推动式投票则是无益的。 –

相关问题