侧边栏壁纸
博主头像
woku博主等级

成功的路上并不拥挤

  • 累计撰写 50 篇文章
  • 累计创建 13 个标签
  • 累计收到 3 条评论

React事件处理

woku
2022-04-22 / 0 评论 / 0 点赞 / 205 阅读 / 3,325 字

事件函数绑定

React元素采用类似于DOM0标准中的事件属性定义的方式

 <button onClick={this.handleClick.bind(this)}>点击</button>
React.createElement('button', {
  onClick: this.handleClick.bind(this)
}, '点击')
class App extends React.Component {
  doSth() {
    console.log('this is something done')
  }
  doSth2(e) {
    console.log('this is something done!')
  }
  render () {
    return (
      <div>
        <button onClick={ this.doSth }>click</button>
        <a href="javascript:;" onClick={ this.doSth2 }>click</a>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('app'))

a标签的href使用javascript:; React会报警告
A future version of React will block javascript: URLs as a security precaution. Use event handlers instead if you can. If you need to generate unsafe HTML try using dangerouslySetInnerHTML instead. React was passed "javascript:;".

class App extends React.Component {
  doSth() {
    console.log('this is something done')
  }
  doSth2(e) {
    console.log(e)  // SyntheticBaseEvent 
    e.preventDefault()
    console.log('this is something done!')
  }
  render () {
    return (
      <div>
        <button onClick={ this.doSth }>click</button>
        <a href="#" onClick={ this.doSth2 }>click</a>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('app'))

e.preventDefault()来阻止默认行为

React中的事件对象e: 是React自己重新定义的,叫做合成基础事件对象 (SyntheticBaseEvent)
这个合成对象是遵守W3C事件对象规范的,不用担心浏览器的兼容性问题

采用类似DOM0这种方式,将事件处理和React元素绑定在一起的原因在于:

  • React一直认为事件处理和视图是有程序上的直接关系的
  • 事件处理和视图写在一起更加直观的表达视图与逻辑直接的关系
  • 更有利于维护

事件处理函数中this的问题

现象

class App extends React.Component {
  doSth() {
    // 默认处理函数的this为undefined
    // ES6中,class模块默认不会事件处理函数中的this再绑定
    console.log(this) // undefined
  }
  render () {
    return (
      <div>
        <button onClick={ this.doSth }>click</button>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('app'))

解决方式

  • bind改变this指向
class App extends React.Component {
  constructor(props) {
    super(props)
    this.doSth = this.doSth.bind(this)
  }
  doSth() {
    console.log(this)
  }
  render () {
    return (
      <div>
        <button onClick={ this.doSth }>click</button>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('app'))
class App extends React.Component {
  constructor(props) {
    super(props)
  }
  doSth() {
    console.log(this)
  }
  render () {
    return (
      <div>
        <button onClick={ this.doSth.bind(this) }>click</button>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('app'))
  • 回调+箭头函数
class App extends React.Component {
  constructor(props) {
    super(props)
  }
  doSth() {
    console.log(this)
  }
  render () {
    return (
      <div>
        <button onClick={ () => this.doSth() }>click</button>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('app'))

render函数每次执行的时候,都会产生一个新的回调
这种方式,如果给子组件的属性传递函数的时候,每次都会创建一个新的回调,子组件每次都接收新的函数,就会触发子组件render
<Test fn={ () => this.doSth() }/>

  • class fields(实验性写法)
class App extends React.Component {
  constructor(props) {
    super(props)
  }
  doSth = () => {
    console.log(this)
  }
  render () {
    return (
      <div>
        <button onClick={ this.doSth }>click</button>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('app'))

事件对象e

class App extends React.Component {
  constructor(props) {
    super(props)
  }
  doSth(p1, p2, p3, e) {
    console.log(p1, p2, p3, e)
  }
  doSth2(p1, p2, p3, e) {
    console.log(p1, p2, p3, e)
  }
  render () {
    return (
      <div>
        <button onClick={ (e) => this.doSth(1, 2, 3, e)}>click</button>
        <button onClick={ this.doSth2.bind(this, 1, 2, 3) }>click</button>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('app'))

注意:
使用回调+箭头函数的方式,要显式的传入事件对象e
使用bind的方式,隐式传入了事件对象e
事件对象e都是在最后一个参数

0

评论区