React学习:事件处理

React :元素构成组件,组件又构成应用。
React核心思想是组件化,其中 组件 通过属性(props) 和 状态(state)传递数据。


一、React 元素 与 DOM 元素 事件处理区别

(1)命名:React 事件使用驼峰命名,而不是全部小写
(2)写法上:
HTML里:

<!-- onclick里c小写,用引号包围内容(想想JSX怎么包裹变量你就懂了)-->
<!-- onclick传递的是函数的执行过程,
    所以还可以像这样:onclick="alert('ss')"-->
<button onclick="activateLasers()">
  Activate Lasers
</button>

React 中:

<!-- onClick里c大写,用{}包围内容-->
<!-- onClick里传递的必须是函数,如要加语句 必须像下面这样:
        <button onClick=()=>{alert('ss')}>其实也是函数 -->
<button onClick={activateLasers}>
  Activate Lasers
</button>

(3)阻止默认行为
在 React 中你不能通过返回 false(即 return false; ) 来阻止默认行为。必须明确调用 preventDefault 。
例如,阻止链接打开一个新页面的默认行为

HTML里:

<a href="#" onclick="
    console.log('The link was clicked.'); 
    return false;
">
  Click me
</a>

而在 React 中, 应该这么写:

function ActionLink() {
      function handleClick(e) {
        e.preventDefault();
        console.log('The link was clicked.');
      }

      return (
        <a href="#" onClick={handleClick}>
          Click me
        </a>
      );
}
ReactDOM.render(
  <ActionLink/>,
  document.getElementById('root')
);

或者这样写

function ActionLink() {
      return (
        <a href="#" onClick={() => {
                e.preventDefault();
                console.log('The link was clicked.');
            }
        }>
          Click me
        </a>
      );
}
ReactDOM.render(
  <ActionLink/>,
  document.getElementById('root')
);

显然第一种写法更方便阅读。


这里需要注意的:我们是 给组件的元素 添加事件,而不是给组件添加事件
例如下面这种写法是错误

function ActionLink() {
      function handleClick(e) {
        e.preventDefault();
        console.log('The link was clicked.');
      }

      return (
        <a href="#">
          Click me
        </a>
      );
}
ReactDOM.render(
  //不是给组件添加事件,是给组件元素添加
  <ActionLink  onClick={handleClick}/>,
  document.getElementById('root')
);


二、处理事件响应的方式

1、使用匿名函数

缺点:当事件响应逻辑比较复杂时,匿名函数的代码量会很大,会导致render函数变得臃肿,不容易直观地看出组件最终渲染出的元素结构。另外,每次render方法调用时,都会重新创建一个匿名函数对象,带来额外的性能开销,当组件的层级越低时,这种开销就越大,因为任何一个上层组件的变化都可能会触发这个组件的render方法。当然,在大多数情况下,这点性能损失是可以不必在意的。

例:

class MyComponent extends React.Component{
  render(){
    //ES6中默认this不与当前对象绑定,
    //而箭头函数解决了this绑定这一问题,它可以将函数体内的this绑定到当前对象
    return(
      <button onClick={
          () => {console.log('hhhh');}
      }>
          click
      </button>
    );
  }
}
ReactDOM.render(
  <MyComponent/>,
  document.getElementById('root')
);

效果:(点击按钮后输出:hhhh)
这里写图片描述

2、使用组件方法
  • 优点:每次render方法的调用,不会重新创建一个新的事件响应函数,没有额外的性能损失。
  • 缺点:使用这种方式要在 构造函数 中 为事件响应的方法 进行手动绑定this: this.handleClick=this.handleClick.bind(this),这是因为ES6 语法的缘故,ES6 Class 的方法默认不会把this绑定到当前的实例对象上,需要我们手动绑定。

例1:

 class MyComponent extends React.Component{
    constructor(props){
      super(props);
      this.state = {number:0};
      //手动绑定this
      this.handleClick = this.handleClick.bind(this);
    }
    handleClick(){
      this.setState({
        number: ++this.state.number,
      });
    }
    render(){
      return(
        <div>
          <div>{this.state.number}</div>
          <button onClick={this.handleClick}>click</button>
        </div>
      );
    }
  }
ReactDOM.render(
  <MyComponent/>,
  document.getElementById('root')
);

效果:同上

例2:

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // 这个绑定是必要的,使`this`在回调中起作用
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

ReactDOM.render(
  <Toggle />,
  document.getElementById('root')
);

效果:狠狠点击我


3、使用属性初始化语法

用到了ES7的特性,目前并非默认支持,需要Babel插件的支持,但是写法最为简洁,也不需要手动绑定this。但是这个特性还处于试验阶段。

 class MyComponent extends React.Component{
    constructor(props){
      super(props);
      this.state = {number:0};
    }
    handleClick = () => {
      this.setState({
        number: ++this.state.number,
      });
    }
    render(){
      return(
        <div>
          <div>{this.state.number}</div>
          <button onClick={this.handleClick}>click</button>
        </div>
      );
    }
  }
ReactDOM.render(
  <MyComponent/>,
  document.getElementById('root')
);

这样一来,再也不用手动绑定this了。但是这个特性还处于试验阶段,默认是不支持的。如果你是使用官方脚手架Create React App 创建的应用,那么这个特性是默认支持的。你也可以自行在项目中引入babel的transform-class-properties插件获取这个特性支持。


三、处理事件响应 函数传参

事件响应函数默认是会被传入一个事件对象Event作为参数的。如果想传入其他参数给响应函数呢?


官方文档是这么说的:
这里写图片描述

但具体什么意思呢?看下面例子你就懂了


方法一:直接使用新参数
class MyComponent extends React.Component{
    constructor(props){
      super(props);
      this.state = {
        list:[1,2,3,4],
        current:1
      };
    }
    handleClick(item,event){
      this.setState({
        current: item,
      });
      alert(item);
    }
    render(){
      return(
        <ul>
          {this.state.list.map(
            (item) => (
              <li className={this.state.current === item ? 'current':''}
                  onClick={(event) => this.handleClick(item,event)}>
                {item}
              </li>
            )
          )}
        </ul>
      );
    }
}
ReactDOM.render(
  <MyComponent/>,
  document.getElementById('root')
);

输出:(实际应用场景中,上面代码应该是像下面一样遍历数组,但第一个项样式会不一样)。点击不同的项后,会alert出该项的值
这里写图片描述

方法二:

把绑定this的操作延迟到render中,在绑定this的同时,绑定额外的参数:

 class MyComponent extends React.Component{
    constructor(props){
      super(props);
      this.state = {
        list:[1,2,3,4],
        current:1
      };
    }
    handleClick(item){
      this.setState({
        current: item,
      });
      alert(item);
    }
    render(){
      return(
        <ul>
          {this.state.list.map(
            (item) => (
              <li className={this.state.current === item ? 'current':''}
                  onClick={this.handleClick.bind(this,item)}
              >
                {item}
              </li>
            )
          )}
        </ul>
      );
    }
}
ReactDOM.render(
  <MyComponent/>,
  document.getElementById('root')
);

效果:同上

方法三:

有没有感觉有鸡肋:虽然你不需要通过bind函数绑定this,但需要bind参数来绑定其他参数。

 class MyComponent extends React.Component{
    constructor(props){
      super(props);
      this.state = {
        list:[1,2,3,4],
        current:1
      };
    }
    handleClick = (item) => {
      this.setState({
        current: item,
      });
      alert(item);
    }
    render(){
      return(
        <ul>
          {this.state.list.map(
            (item) => (
              <li className={this.state.current === item ? 'current':''}
                  onClick={this.handleClick.bind(undefined,item)}
                  //或onClick={this.handleClick.bind(null,item)
              >
                {item}
              </li>
            )
          )}
        </ul>
      );
    }
}
ReactDOM.render(
  <MyComponent/>,
  document.getElementById('root')
);

不管你在响应函数中有没有显式的声明事件参数Event,React都会把事件Event作为参数传递给响应函数,且参数Event的位置总是在其他自定义参数的后面。例如,在《方法二、方法三 》中, handleClick的参数中虽然没有声明Event参数,但你依然可以通过 arguments[1]获取到事件Event对象。


猜你喜欢

转载自blog.csdn.net/b954960630/article/details/79858083