16、react 中的高阶函数和柯里化
react 中的高阶函数和柯里化
这一篇博文我们说一下 高阶函数 和 柯里化,这两个次可能第一次听说,不知道是啥意思,我们先不管他哈,记得上一篇博客,我们实现了一个登陆的案例是吧?输入用户名和密码,点击登陆按钮,弹出用户名和密码输入的问题,我们跟随着这个案例来思考一些问题。
上篇博客案例
代码:
<!-- 此处必须写 text/babel --><script type="text/babel">// 创建组件class Login extends React.Component {state = { username: '', password: '' }handleSubmit = (event) => {event.preventDefault() // 阻止默认事件,即表单提交组织const { username, password } = this.statealert(`你输入的账号是 ${username},你输入的密码是 ${password}`)}saveUsername = (event) => {this.setState({ username: event.target.value })}savePassword = (event) => {this.setState({ password: event.target.value })}render() {return (<form onSubmit={this.handleSubmit}>账号:<input onChange={this.saveUsername} type="text" name="username" /> <br />密码:<input onChange={this.savePassword} type="passwofd" name="password" /><br /><button>登 录</button></form>)}}// 渲染组件ReactDOM.render(<Login />, document.getElementById("app"))</script>
效果:
高阶函数
我们看上面的代码哈,我们在保存账号密码的时候呢,写了两个含糊,在输入框改变的时候分别调用的这两个函数,但是我们观察这两个函数:
// 保存账号到状态saveUsername = (event) => {this.setState({ username: event.target.value })}// 保存密码到状态savePassword = (event) => {this.setState({ password: event.target.value })}
有没有觉得这两个方法高度相似?这是只保存密码和账号,如果业务比较大,比如注册,需要保存用户名、密码、确认密码、邮箱、电话、性别、地址… 这样的话会异常的繁琐,代码会特别的冗余。有没有什么好的办法解决呢?
比如我们就写一个方法,根据传进的参数确定保存的是啥,怎么修改?
那在输入框的change事件里面,就需要修改一下吧
账号:<input onChange={this.saveFormData('username')} type="text" name="username" /> <br />
密码:<input onChange={this.saveFormData('password')} type="passwofd" name="password" /><br />
这样改吧?都用 saveFormData
方法,根据传进的是 username
还是 password
来判断保存的是啥。
那我们得写一个 saveFormData
方法吧?那写一个,这样的话,之前的两个保存方法就可以舍弃了。
// 保存表单数据到状态中
saveFormData =(dataType) =>{console.log(dataType)
}
dataType
就是我们传进的 username
或者是 password
吧?这样是有问题的,什么问题呢?之前博客点击事件的时候我们说过,onChange={ }
这个花括号里面需要写 js 表达式,如果我们给方法加上 ()
了的话,他会被直接执行对吧?
我们直接刷新看一下效果:
我们看到哈,一刷新页面,控制台直接打印了是吧?这个是肯定的原因也说了。然后我在输入框输入数据之后,onChange
事件就不执行了,这是为啥?其实也好理解,因为 onChange
接受的是 { }
里面 js 表达式返回的值
吧?但是这个 saveFormData
函数有返回值吗?没有!所以是 undefined。onChange 赋值了个 undefined
,所以不会被触发,就相当于没有用。就是这个原因。
怎么解决呢?思考一下。
既然 onChange
需要的是一个方法,那就给他一个方法。
// 保存表单数据到状态中saveFormData =(dataType) =>{return () => {}}
这样就可以啦吧!那你说,onChange
最后回调的是 saveFormData
,还是 saveFormData 里面返回的箭头函数
?
很显然是saveFormData 里面返回的箭头函数
啊!
所以说 返回的箭头函数可以获取到 event
吧?不确定就打印一下,同时我们把 dataType
也打印一下。
// 保存表单数据到状态中saveFormData = (dataType) => {return (event) => {console.log(dataType, event.target.value)}}
保存看效果:
哎哟,这不就都拿到了嘛,保存的是啥,值是啥,都拿到了。接下来就是简单的保存进状态了。
怎么保存进状态,很多宝子很聪明,是这样写的。
// 保存表单数据到状态中saveFormData = (dataType) => {return (event) => {this.setState({ dataType: event.target.value })}}
额~ 这样肯定是不可以的哈!
你看截图,如果这样写了的话,保存起来之后,既没有改变 username,也没有改变 password,而是创建了新的 dataType 保存了。那正确的保存方式怎么写呢?
// 保存表单数据到状态中saveFormData = (dataType) => {return (event) => {this.setState({ [dataType]: event.target.value })}}
这样子就可以啦哈
为什么这样写,我说一下吧。首先我们回顾一下 对象的相关知识。
对象的相关知识
假设我有一个变量 a
的值是 name
,有一个空对象 obj
,我想把 obj
变成 { name: "我是ed." }
怎么做?
<script>let a = "name"let obj = {} // {name: '我是ed.'}obj.name = '我是ed.'console.log(obj)</script>
上面代码是没有问题的吧?
当然没问题,但是 a
没有用到啊,如果要用 a
呢?
obj[a] = '我是ed.'console.log(obj)
这样子就可以了吧?所以说
this.setState({ [dataType]: event.target.value })
这个地方的 dataType
加上中括号就可以了。
好的,这样保存状态尽管在两个地方需要,但是只需要一个函数就可以实现了!
<!-- 此处必须写 text/babel --><script type="text/babel">// 创建组件class Login extends React.Component {state = { username: '', password: '' }handleSubmit = (event) => {event.preventDefault() // 阻止默认事件,即表单提交组织const { username, password } = this.statealert(`你输入的账号是 ${username},你输入的密码是 ${password}`)}// 保存表单数据到状态中saveFormData = (dataType) => {return (event) => {this.setState({ [dataType]: event.target.value })}}render() {return (<form action="http://www.baidu.com" onSubmit={this.handleSubmit}>账号:<input onChange={this.saveFormData('username')} type="text" name="username" /> <br />密码:<input onChange={this.saveFormData('password')} type="passwofd" name="password" /><br /><button>登 录</button></form>)}}// 渲染组件ReactDOM.render(<Login />, document.getElementById("app"))</script>
效果很完美
案例我们改造完了,那我们改造的 saveFormData
函数就是高阶函数
// 保存表单数据到状态中saveFormData = (dataType) => {return (event) => {this.setState({ [dataType]: event.target.value })}}
我们看一下高阶函数的定义:
高阶函数:如果一个函数不符合下面两个规范中的任意一个,那该海曙就是高阶函数。
- 若A函数,接受的参数是一个函数,那个A就可以称之为高阶函数。
- 若A函数,调用的返回值依然是一个函数,那A就可以称之为高阶函数。
常见的高阶函数:Promise、setTimeout、arr.map() 等等。
saveFormData 是根据第二条来定义的,同时这个函数使用了 函数柯里化
。
什么是函数的柯里化
呢?
函数的柯里化:通过函数调用继续返回函数的方式,实现多次接受参数最后统一处理的函数编码形式。
这个函数柯里化不好定义哈,我们看一个例子,一个典型的函数柯里化的例子,数字求和:
<script>function sum(a) {return (b) => {return (c) => {return a + b + c}}}const result = sum(1)(2)(3)console.log(result)</script>
执行结果出来了,很正确!
如果单纯看这个例子的话,觉得这个求和的例子简直是有病!
但是我们这个登陆的案例,不就是一个很合理的柯里化应用场景吗?我想直接穿一个参数告诉存储方法我要存的是啥,我也想告诉这个存储方法我存储的值是多少,但是 存储的是什么我可以告诉他,但是值是多少也就是 event 是多少,我告诉不了,因为 event 是 react 是回调的时候自动生成出来的,我们不能干涉,所以就是用函数的柯里化解决问题。
OK,今天这部分的内容就到这里了。辛苦了。
【本部分相关代码资料】:我是
16、react 中的高阶函数和柯里化相关推荐
- [转载] 高阶函数和柯里化
参考链接: Python中的First Class函数 高阶函数 一等公民 函数在Python是一等公民(First-Class Object)函数也是对象,是可调用对象函数可以作为普通变量,也可以作 ...
- js 高阶函数之柯里化
博客地址:https://ainyi.com/74 定义 在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且 ...
- React 中的高阶组件及其应用场景
本文目录 什么是高阶组件 React 中的高阶组件 属性代理(Props Proxy) 反向继承(Inheritance Inversion) 高阶组件存在的问题 高阶组件的约定 高阶组件的应用场景 ...
- python中的高阶函数
python中的高阶函数 文章目录: 1 什么是高阶函数? 1.1 高阶函数:一个函数的`函数名`作为参数传给另外一个函数 1.2 高阶函数:一个函数返回值(return)为另外一个`函数` 2 py ...
- React中的高阶组件
React中的高阶组件 高阶组件HOC即Higher Order Component是React中用于复用组件逻辑的一种高级技巧,HOC自身不是React API的一部分,它是一种基于React的组合 ...
- 【Kotlin】Kotlin 语言集合中的高阶函数详解 ( 数据类 data class | maxBy | minBy | filter | map | any | count | find )
文章目录 I . List 集合高阶函数引入 II . Kotlin 数据类 ( data class ) III . Java 代码 与 Kotlin 代码实现对比 ( 查询年龄最大的 ) IV . ...
- 1 access中iif函数中的_JavaScript中的高阶函数
前言 在 JavaScript 的学习过程中,我们可能或多或少地接触过高阶函数.那么,我们自己对此是否有一个明确的定义,或者说很熟练的掌握这些用法呢 如果文章中有出现纰漏.错误之处,还请看到的小伙伴多 ...
- Kotlin中的高阶函数
博客地址sguotao.top/Kotlin-2018- 在Kotlin中,高阶函数是指将一个函数作为另一个函数的参数或者返回值.如果用f(x).g(x)用来表示两个函数,那么高阶函数可以表示为f(g ...
- scala中的高阶函数_Scala中的高阶函数(HOF)
scala中的高阶函数 Higher Order Functions (HOF) in Scala are the very core of this functional programming l ...
最新文章
- CSS中的字体属性和使用
- hive报错(1)MoveTask/HIVE return code 1、2、3
- Netlib文件转化为mps文件
- C# Excel数据有效性
- 设置上传文件的最大大小
- 如何启用计算机超级账户,Windows7启用超级管理员账户的方法
- Oracle_Rac_BackgroudProcess
- 为什么说Java是2021年最值得学的技术?
- 用开源NAC阻止非法网络访问
- 琥珀项目:较小的,面向生产力的Java语言功能
- javascript练习----复选框全选,全不选,反选
- lnmp mysql 远程访问_LNMP环境下 远程连接mysql数据库
- 【转】我应该直接学Swift还是Objective-C?
- 阿里云 POSTFIX 邮件服务 PHP
- java生成图表_【JAVA】POI生成EXCEL图表(柱状图、折线等)
- 2018 Google IO大会来了
- PNG-的IDAT解析
- python输入名字配对情侣网名_名字匹配情侣网名
- 天天向上答案python_天天向上的力量python(举一反三)
- CMake中使用get_target_property判断Target是否存在