react中事件处理与柯里化的实现

目录
  • 1. 事件处理
    • 阻止默认行为
    • 合成事件
  • 2. 柯里化
    • 柯里化的目的
    • 一个简单的例子

1. 事件处理

React 中元素也可接受、处理事件,但是在语法上有一点不同。

在React 中所有事件的命名采用的是小驼峰,而非原生 DOM 的纯小写,所有事件需要我们传入一个函数,而非字符串。

例如:

const Button = () => {
    const handleClick = () => {
        console.log('click')
    }
    return <button onClick={handleClick}>click button</button>
}

当事件的回调函数比较简单时,我们也可以简写箭头匿名函数,例如:

const Button = () => {
    return (
        <button
            onClick={() => console.log('click')}
        >
            click button
        </button>)
}

阻止默认行为

在React 中不能通过返回 false 来阻止默认行为,例如表单提交、a标签跳转。我们必须要通过显式调用 preventDefault 函数,来阻止这些默认行为。

const Link = () => {
    return <a
        href="https://www.baidu.com" rel="external nofollow"  rel="external nofollow"
        onClick={(e) => e.preventDefault()}
    >
        link
    </a>
}

合成事件

在 React 中几乎所有的事件处理函数,都是一个 (event)=>void 函数,如果我们使用 typescript,可以清晰的看到每个事件对应的函数类型,React 自身也声明了很多的事件与事件处理函数类型,例如鼠标事件:MouseEvent<T = Element>MouseEventHandler<T = Element>,我们在使用时可以根据自己的喜欢,是定义函数类型还是定义参数类型,就像这样:

const Link = () => {
    const handleClick = (e: MouseEvent) => {
        e.preventDefault()
        console.log('click')
    }
    const handleMouseEnter:MouseEventHandler = (e) => {
        console.log('mouse enter')
    }
    return <a
        href="https://www.baidu.com" rel="external nofollow"  rel="external nofollow"
        onMouseEnter={handleMouseEnter}
        onClick={handleClick}
    >
        link
    </a>
}

在 React 中,所有事件都是 React 根据 W3C 规范定义的合成事件,所以我们完全不用担心兼容性问题,React 事件与原生事件不完全相同。

点击此处查看合成事件文档

2. 柯里化

柯里化这个名称对于 Android 开发可能有点陌生,因为我们一般使用 Java 开发,因为早期的 Java 不支持函数式编程(FP),而柯里化是一个函数式编程思想。

简而言之是将一个多参函数变成单参数函数,举个栗子:

//柯里化后的单参数函数
function sumCurrying(a) {
  return (b) => {
    return (c) => {
      return a + b + c;
    };
  };
}
//普通的多参数函数
function sumNormal(a, b, c) {
  return a + b + c
}
console.log(sumCurrying(1)(2)(3));
console.log(sumNormal(1, 2, 3));

柯里化的本质,就是高阶函数的一个特性:函数的返回值可以是一个函数。

上面的例子,似乎有点脱裤子放屁,看似毫无意义。但实际工程中,柯里化是一个非常实用的小 trick。最常用在事件处理需要传入值的场景。

我们在上面说过了,React 中的事件回调函数是有固定的函数类型的,几乎都是 (event)=>void 函数。我们需要传入一些参数给这个事件处理函数呢?

const List = () => {
    const list = [
        { id: 1, name: 'tom' },
        { id: 2, name: 'jerry' },
        { id: 3, name: 'jack' },
        { id: 4, name: 'lily' },
    ]
    const handleClick = (id: number) => {
        console.log(id)
    }
    return <ul>
        {list.map(item => <li
                onClick={() => handleClick(item.id)}
                key={item.id}
            >
                {item.name}
            </li>
        )}
    </ul>
}

这看起来似乎很不优雅,我们已经声明了 handle 函数,却又不得不在事件处理函数中写行内的箭头函数,如何才能更加优雅的处理呢?

其实很简单,我们只需要在原本的 handle 函数中,插入一个箭头即可,就像这样:

//before
const handleClick = (id: number) => {
  console.log(id)
}
//after
const handleClick = (id: number) => (e:MouseEvent) => {
  console.log(id)
}

然后我们的 onClick 事件回调函数就可以改成 onClick={handleClick(item.id)} ,这样看起来是不是就更加优雅了呢?

其实这种设计思想可以说是一说就透,只不过我现在告诉你,这种思想就叫做:柯里化

柯里化的目的

你可能会问我柯里化看起来只是让我们的代码优雅了一点,在目前看来似乎没有什么本质上的变化。

但其实柯里化帮助我们实现了函数的一变多,我们用一个日志输出的函数作为例子:

//原始函数
const log = (date, importance, message) => {
  alert(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`);
}
//柯里化
const logCurry = (date) => (importance) => (message) => {
  alert(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`);
}

柯里化后,函数变成这样调用:logCurry(new Date())("DEBUG")("some debug");

现在我们相当于拥有这些函数:

// logNow 会是带有固定第一个参数的日志的函数
let logNow = logCurry(new Date());

// 使用它
logNow("INFO", "message"); // [HH:mm] INFO message

// debugNow 会是带有固定第一个参数与第二个参数的函数
let debugNow = logNow("DEBUG");

debugNow("message"); // [HH:mm] DEBUG message

看起来只是增加了几个箭头,实际上我们函数的灵活性大为增加。通过固定不同的参数,我们从一个函数声明获得了多个函数。

一个简单的例子

const Form = () => {
   const [form, setForm] = React.useState({});
   const update = (name) => (event) => {
     setForm({
       ...form,
       [name]: event.target.value,
     });
   }
   const handleSubmit = (event) => {
     event.preventDefault();
     alert(`${JSON.stringify(form)}`);
   }
   return (
     <div>
       <h1>柯里化表单</h1>
       <FormItem label="用户名" name='username' update={update} />
       <FormItem label="昵称" name='nickname' update={update} />
       <FormItem label="邮箱" name='email' update={update} />
       <button onClick={handleSubmit}>提交</button>
     </div>
   )
 }

 const FormItem = ({ label, name, update }) => {
   return (
     <div style={{ 'display': 'flex' }}>
       <label>{label}</label>
       <input onChange={update(name)} type="text" placeholder={`请输入${label}`} />
     </div>
   );
 };

到此这篇关于react中事件处理与柯里化的实现的文章就介绍到这了,更多相关react 事件处理与柯里化内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • React事件处理的机制及原理

    React中的事件处理 在React元素中绑定事件有两点需要注意: (1)在React中,事件命名采用驼峰命名方式,而不是DOM元素中的小写字母命名方式.例如onclick要写成onClick,onchange要写成onChange等. (2)处理事件的响应函数要以对象的形式赋值给事件属性,而不是DOM中的字符串形式.例如在DOM中绑定一个点击事件应该写成: <button onclick="clickButton()"> Click </button> 而在R

  • React的事件处理你了解吗

    目录 一.React的事件处理 1.与DOM事件处理的不同之处 (1)React事件的命名方式:小驼峰方式,DOM的命名方式是小写 (2)事件处理函数是以对象的方式赋值,而不是以字符串的方式赋值 (3)阻止默认事件的方式不同 2.React中事件处理函数的定义 (1)使用ES6的箭头数 (2)在构造函数中进行绑定:将事件处理函数作为类的成员函数 (3)在render函数中绑定this (4)React中事件处理函数 (5)注意事项 3.事件处理中的参数传递 (1)直接传递参数 (2)在定义UI控

  • react中事件处理与柯里化的实现

    目录 1. 事件处理 阻止默认行为 合成事件 2. 柯里化 柯里化的目的 一个简单的例子 1. 事件处理 React 中元素也可接受.处理事件,但是在语法上有一点不同. 在React 中所有事件的命名采用的是小驼峰,而非原生 DOM 的纯小写,所有事件需要我们传入一个函数,而非字符串. 例如: const Button = () => { const handleClick = () => { console.log('click') } return <button onClick={

  • 浅谈JS中的反柯里化( uncurrying)

    反柯里化 相反,反柯里化的作用在与扩大函数的适用性,使本来作为特定对象所拥有的功能的函数可以被任意对象所用. 即把如下给定的函数签名, obj.func(arg1, arg2) 转化成一个函数形式,签名如下: func(obj, arg1, arg2) 这就是 反柯里化的形式化描述. 例如,下面的一个简单实现: Function.prototype.uncurrying = function() { var that = this; return function() { return Func

  • 详解JS中的柯里化(currying)

    何为Curry化/柯里化? curry化来源与数学家 Haskell Curry的名字 (编程语言 Haskell也是以他的名字命名). 柯里化通常也称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果. 因此柯里化的过程是逐步传参,逐步缩小函数的适用范围,逐步求解的过程. 柯里化一个求和函数 按照分步求值,我们看一个简单的例子 var concat3Words = function (

  • 深入剖析JavaScript中的函数currying柯里化

    curry化来源与数学家 Haskell Curry的名字 (编程语言 Haskell也是以他的名字命名).   柯里化通常也称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果. 因此柯里化的过程是逐步传参,逐步缩小函数的适用范围,逐步求解的过程. 柯里化一个求和函数 按照分步求值,我们看一个简单的例子 var concat3Words = function (a, b, c) { r

  • javascript中利用柯里化函数实现bind方法

    柯理化函数思想:一个js预先处理的思想:利用函数执行可以形成一个不销毁的作用域的原理,把需要预先处理的内容都储存在这个不销毁的作用域中,并且返回一个小函数,以后我们执行的都是小函数,在小函数中把之前预先存储的值进行相关的操作处理即可: 柯里化函数主要起到预处理的作用: bind方法的作用:把传递进来的callback回调方法中的this预先处理为上下文context; /** * bind方法实现原理1 * @param callback [Function] 回调函数 * @param con

  • 浅谈JS中的bind方法与函数柯里化

    绑定函数bind()最简单的用法是创建一个函数,使这个函数不论怎么调用都有同样的this值.不同于call和apply只是单纯地设置this的值后传参,它还会将所有传入bind()方法中的实参(第一个参数之后的参数)与this一起绑定. 关于这个特性看<JS权威指南>原文的例子: var sum = function(x,y) { return x + y }; var succ = sum.bind(null, 1); //让this指向null,其后的实参也会作为实参传入被绑定的函数sum

  • 深入解析JavaScript中函数的Currying柯里化

    引子 先来看一道小问题: 有人在群里出了到一道题目: var s = sum(1)(2)(3) ....... 最后 alert(s) 出来是6  var s = sum(1)(2)(3)(4) ....... 最后 alert(s) 出来是10  问sum怎么实现? 刚看到题目,我第一反应是sum返回的是一个function,但是没有最终实现,印象中看到过类似的原理,但是记不清了.   后来同事说,这个是叫柯里化, 实现方法比较巧妙: function sum(x){ var y = func

  • javascript中利用柯里化函数实现bind方法【推荐】

    • 柯理化函数思想:一个js预先处理的思想:利用函数执行可以形成一个不销毁的作用域的原理,把需要预先处理的内容都储存在这个不销毁的作用域中,并且返回一个小函数,以后我们执行的都是小函数,在小函数中把之前预先存储的值进行相关的操作处理即可: • 柯里化函数主要起到预处理的作用: • bind方法的作用:把传递进来的callback回调方法中的this预先处理为上下文context; /** * bind方法实现原理1 * @param callback [Function] 回调函数 * @par

  • JS中精巧的自动柯里化实现方法

    以下内容通过代码讲解和实例分析了JS中精巧的自动柯里化实现方法,并分析了柯里化函数的基础用法和知识,学习一下吧. 什么是柯里化? 在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术.这个技术由 Christopher Strachey 以逻辑学家 Haskell Curry 命名的,尽管它是 Moses Schnfinkel 和 Gottlob Frege 发明的. 理论看着头大?没

  • js中闭包结合递归等于柯里化原理解析

    引言 我们不妨以两数相加为例子,递进说明. 我们通常是这样写一个函数来求得 两数相加 的值: function sum(a,b){ console.log(a+b) } sum(1,2) 这样写一点毛病没有! 不过呢?问题总会在发展中产生,产品经理又要加一个值,需求:三数相加: 咱通常来说,第一时间,就在原基础上,直接再加一个参数就是了: 于是,修改后像是这样: function sum(a,b,c){ console.log(a+b+c) } sum(1,2,3) 问:这样写,有毛病吗?? 答

随机推荐