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 事件处理与柯里化内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!