最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • React 为循环创建的元素绑定事件处理并传参

    正文概述 掘金(victorsonger)   2021-02-01   866

    场景

    设想我们现在有一个很长很长的数组,要根据这个数组来循环创建一组元素,每个元素上需要绑定点击事件处理程序;我们需要在事件处理函数中拿到当前被点击元素对应的数组项信息。

    官方操作

    React官方文档对于这种场景给出了常用处理方案:

    在循环中,通常我们会为事件处理函数传递额外的参数。例如,若 id 是你要删除那一行的 ID,以下两种方式都可以向事件处理函数传递参数:

    <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
    <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
    

    上述两种方式是等价的,分别通过箭头函数和 Function.prototype.bind 来实现。

    在这两种情况下,React 的事件对象 e 会被作为第二个参数传递。如果通过箭头函数的方式,事件对象必须显式的进行传递,而通过 bind 的方式,事件对象以及更多的参数将会被隐式的进行传递。

    官方操作的问题

    上述方法存在的最明显的问题在于,无论是使用箭头函数,还是使用.bind(),每次render的时候都会重新创建事件处理函数。

    箭头函数自不必说。而在render中使用.bind(),其实等同于每次render的时候,React都要对数组每一项先执行一下这个.bind(),拿它返回的结果当做此元素绑定的事件处理方法。显然,每一次执行.bind()返回的都是一个新的值(这和在constructor中先bind一次,然后render中直接使用bind的结果原理不同)。

    如果我们的数组有100多项,那每一次render的时候就要重新创建100多个事件处理函数。更糟糕的是,如果我们是将事件处理函数作为 prop 传入循环创建的子组件,可能会导致这些子组件都进行额外的重新渲染。

    优化思路

    我们希望循环创建的所有元素,其绑定的事件处理函数都指向同一个函数对象,并且不会在每次render 的时候发生变化。这就要求我们不能把循环项中的信息作为入参直接传入事件处理函数

    当事件处理函数执行时,我们一定能获取到的信息是当前触发事件的event对象。所以我们可以考虑从event对象中获取我们需要的信息,而非显式地传入参数。

    如何在event对象中拿到与当前数组项对应的信息呢?

    dataset

    HTMLElement.dataset属性允许无论是在读取模式和写入模式下访问在 HTML或 DOM中的元素上设置的所有自定义数据属性(data-*)集。

    看一下MDN上的示例就明白了:

    <div id="user" data-id="1234567890" data-user="johndoe" data-date-of-birth>John Doe
    </div>
    
    var el = document.querySelector('#user');
    
    // el.id == 'user'
    // el.dataset.id === '1234567890'
    // el.dataset.user === 'johndoe'
    // el.dataset.dateOfBirth === ''
    
    

    因此,我们可以进行这样的操作:在render中,为每一项循环创建的元素添加dataset属性,将当前数组项的信息绑定上去。然后在事件处理函数中通过event.target.dataset取到绑定的信息

    如果数组对象数据较为复杂,直接绑定在dataset上会导致对应的html标签挂上一长串信息,而且都是string格式,拿到之后还要再费力解析。所以我们也可以只绑定数组项对应的索引,然后在事件处理函数中根据索引去取到对应的数组对象。

    实践示例

    import React, { Component } from "react";
    class ClassComponent extends Component {
      constructor(props) {
        super(props);
        this.state = {
          curText: "",
          toClickList: [
            {
              id: 1,
              text: "我是1",
            },
            {
              id: 2,
              text: "我是2",
            },
            {
              id: 3,
              text: "我是3",
            },
          ],
        };
        this.setText = this.setText.bind(this);
      }
    
      // 事件处理函数
      setText(event) {
        const index = event.target.dataset.index
        const item = this.state.toClickList[index];
    
        this.setState({
          curText: item.text
        })
      }
    
      render() {
        const { toClickList } = this.state;
        return (
          <div>
            {toClickList.map((item, index) => {
              return (
                {/* 在循环中为每一项元素绑定dataset属性。这里我们把index绑上去 */}
                <button onClick={this.setText} key={item.id} data-index={index}>
                  {item.text}
                </button>
              );
            })}
            <br/>
    
            当前点击的text:{this.state.curText}
          </div>
        );
      }
    }
    
    export default ClassComponent;
    

    总结

    我们通过在循环中为每一项元素绑定dataset属性,把数组对应项的索引index绑定在DOM上,再在事件处理函数中通过event.target.dataset.index取到当前事件对应数组元素的索引,进而取到原数组下的对象信息。

    其实不只是在React的class组件中,在其他任何需要给循环创建的元素绑定事件监听的场景中,都可以通过这种思路来避免重复创建事件处理函数。

    参考目录

    React 事件处理

    React Dynamic Events


    起源地下载网 » React 为循环创建的元素绑定事件处理并传参

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元