前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【React】学习笔记(一)——React入门、面向组件编程、函数柯里化

【React】学习笔记(一)——React入门、面向组件编程、函数柯里化

作者头像
鸡先生
发布2022-10-29 17:30:40
5K0
发布2022-10-29 17:30:40
举报
文章被收录于专栏:鸡先生鸡先生

课程原视频:https://www.bilibili.com/video/BV1wy4y1D7JT?p=2&spm_id_from=pageDriver

目录

学前需掌握以下知识点

  • 判断this的指向
  • class(类)
  • ES6语法规范
  • npm/yarn包管理器
  • 原型、原型链
  • 数组常用方法
  • 模块化

一、React 概述

用于构建用户界面的 Javascript 库,它主要专注于界面与视图。采用组件化模式、声明式编码,提高开发效率及组件复用率。在React Native中可以使用React语法进行移动端开发。使用虚拟DOM+优秀的Diffing算法,尽量减少与真实DOM的交互。

1.1、React 开发背景

由Facebook开发,且开源

  1. 起初由 Facebook的软件工程师 Jordan Walke 创建
  2. 于2011年部署于Facebook的newsfeed
  3. 随后在2012年部署于Instagram
  4. 2013年5月宣布开源 ...

近十年“陈酿”被各大厂广泛使用

1.2、模块与组件、声明式与组件化

模块 随着业务逻辑增加,代码越来越多且复杂。人们更倾向于将复杂大块的业务逻辑拆分成小模块,每个模块复杂一部分内容。可以理解为向外提供特定功能的js程序,一般就是一个js文件。这样写的好处是复用js,简化了js的编写,提高了js运行效率

声明式 React 使创建交互式 UI 变得轻而易举。为你应用的每一个状态设计简洁的视图,当数据变动时 React 能高效更新并渲染合适的组件。

以声明式编写 UI,可以让你的代码更加可靠,且方便调试。

组件 用来实现局部功能效果的代码和资源的集合(html/css/js/image等等)。一个界面的功能太复杂,而且资源浪费也很多。React将各个不同的功能拆分为组件,每个组件只负责特定区域中的数据展示,如Header组件只负责头部数据展示。这样写可以复用代码,简化项目编码,提高运行效率

组件化

构建管理自身状态的封装组件,然后对其组合以构成复杂的 UI。

由于组件逻辑使用 JavaScript 编写而非模板,因此你可以轻松地在应用中传递数据,并保持状态与 DOM 分离。

1.3、虚拟DOM与真实DOM

image
image

当我们需要修改DOM属性时,真实DOM是将一个新的界面直接覆盖在旧界面上,原来页面上已经有的数据就浪费了,假如原来有100条数据,当数据发生变化了就得产生100+n个DOM

image
image

而React 怎么做的呢,当数据发生变化时,将真实DOM生成对应虚拟DOM,但并不会将原来的虚拟DOM丢弃,它会进行虚拟DOM的比较,如果一样的话就不会给他生成真实的DOM,同样100条数据,发生变化了,它只会渲染多出来的数据

关于虚拟DOM 本质是Object类型的对象(一般对象)。虚拟DOM比较‘轻’,真实DOM比较‘重’,因为虚拟DOM是React内部在用,无需真实DOM上那么多属性。虚拟DOM最终会转换成真实DOM,呈现在页面上。

二、React 入门

准备工作 1.创建项目文件 2.下载依赖包

image
image

链接:https://pan.xunlei.com/s/VN3NvR6dEbf7OToBaxa14HWYA1?path=ids6

3.引入依赖包 将上面三个文件托到我们项目中,注意!引用必须按照以下顺序进行

代码语言:javascript
复制
<! -- 引入react核心库-->
<script type="text/javescript" src=" ../React学习/季s/react.development. js"> </script>
<l --引入react-dom,用于支持react操作DOM -->
<script type="text/javescript" src="../React学习/3s/react-dom.development.js"></script>
<! --引入babel.用于将Jsx转为js-->
<script type="text/javescript" src="../React 学习/Js/babel.min.js"></script>

引入react.development 、 react-dom.development 这两个库后,全局变量中多了React 和 ReactDOM两个变量。

2.1、Hallo React

开始写代码

代码语言:javascript
复制
<script type="text/babel">/*此处一定要写babel */
  //1.创建虚拟DOM
  const VDOM = <h1>Hello,React</h1>/* 此处一定不要写引号,因为不是字符串*/
  //2.渲染虚拟DOM到页面
  ReactDOM.render(VDoM,document.getElementById( 'test' ))
</script>

script标签的type属性必须写text/babel,如果不写默认为JavaScript

运行效果

image
image

2.2、JSX语法规则

在React 中的语法是JSX 并不是JS 有一定区别。 ①:定义虚拟DOM时,不要使用引号

代码语言:javascript
复制
const VDOM = (
    <h2 id="myId">
        <span>myData</span>
    </h2>
)

这是个错误示范,这样输出的结果就是,myData还是有,但h2标签id为空

②:标签中混入JS表达式时要用{}

代码语言:javascript
复制
const VDOM=(
      <h2 id={myId.toLowerCase()}>
         <span>{myData.toLowerCase()}</span>
      </h2>
)

toLowerCase()这个API是将ID字符都变成小写的意思

③:样式的类名指定不要使用class,而是className

代码语言:javascript
复制
.title{
        color:white;
}

const VDOM=(
    <h2 calssName="title" id={myId.toLowerCase()}>
        <span>{myData.toLowerCase()}</span>
    </h2>
)

因为class是ES6编码格式中的关键字,JSX为了避免发生冲突于是便这么写。像这样的设计React中还有许多

④:内联样式,要用style={{key:value}}的形式去写,否则直接报错

代码语言:javascript
复制
const VDOM=(
    <h2 calssName="title" id={myId.toLowerCase()}>
        <span style={{color:'while',fontsize:'29px'}}>{myData.toLowerCase()}</span>
    </h2>
)

⑤:只有一个根标签

image
image

向上面这样写就会飘红,因为跟标签是(h2)并且有两个,需要一个容器给包起来

代码语言:javascript
复制
const VDOM=(
      <div>
         <h2 calssName="title" id={myId.toLowerCase()}>
             <span style={{color:'while',fontsize:'29px'}}>{myData.toLowerCase()}</span>
        </h2>
        <h2 calssName="title" id={myId.toLowerCase()}>
          <span style={{color:'while',fontsize:'29px'}}>{myData.toLowerCase()}</span>
        </h2>
     </div>
)

⑥:标签必须闭合 与Html中的标签同理,必须有头有尾,或者写成自结束标签,如<input/>

⑦:标签首字母 React中非常讲究细节。 1)若小写字母开头

  • 将改标签转为html同名元素,若html中无该标签的同名元素,则报错

2)若大写字母开头

  • react就去渲染对应的组件,若组件没有定义,则报错

JSX中写注释格式 {/ 代码块 /}

JSX语法小练习 需求: 动态展示如下列表

image
image
代码语言:javascript
复制
//模拟一些数据
const data=['Angular','React','Vue']

const VDOM=(
    <div>
        <h1>前端js框架列表</h1>
        <ul>
        {//还记得上面的JSX语法规则嘛:标签中混入JS表达式时要用{}
         //但是并没有说JS代码哦,所以这里我们for循环直接传值写
         //map(vaule,key)加工数组
            data.map((item,index)=>{
                return <li key={index}>{item}</li>
          })
        }
        </ul>
    </div>
)

2.3、JS语句(代码)与JS表达式的区别

表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方,如

代码语言:javascript
复制
 (1). a
 (2). a+b
 (3). demo(1)
 (4). arr.map()
 (5). function test () {}

语句(代码):

代码语言:javascript
复制
 (1) . if() {}
 (2) . for() {}
 (3) . swich() {case:xxxx}

React 接收到数组数据时会自动帮我们遍历,如果传的是对象会报错 Object are not valid as a React child

三、面向组件编程

官方给了我们两种组件化编程的方式:

3.1、函数式组件

从简到难。我们回顾一下什么是组件,组件:用来实现局部功能效果的代码和资源的集合,那一个组件里面就得包含 布局(html)、样式(css)、交互(js)、资源(image)等等。

所谓函数式组件如字面意思,使用函数的形式编写组件。该组件具有函数的一些特征

代码语言:javascript
复制
<script type="text/babel">
    function MyComponent(){
        return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>
  }

  ReactDom.render(<MyComponent/>,document.getElementById('test'))
  /*
    执行ReactDom.render(<MyComponent/>,document......之后发生什么?
      1.React解析组件标签,找到MyComponent组件。
      2.发现组件是使用函数定义的,随后调用该函数
      3.将返回的虚拟DOM转化为真实DOM,随后呈现在页面中
  */
</script>

注意事项

  1. 开头字母大写(小写会被判断为html标签
  2. 组件标签必须闭合
  3. 函数必须有返回值
  4. render()方法的第一个参数注意写组件标签,不要直接写组件名字
  5. babel转意时开启严格模式,禁止this指针指向window

3.2、类式组件

在学习类式组件之前我们先复习一下类的基本知识

  1. 类中的构造器不是必须写的,要对实例进行一些初始化的操作,如添加指定属性时才写
  2. 如果A类继承了B类,且A类中写了构造器,那么A类构造器中的super是必须要调用的
  3. 类中所定义的方法,都放在了类的原型对象上,供实例去使用
代码语言:javascript
复制
<script type="text/babel">
  //1.创建类式组件
  class MyComponent extends React.Component {
    render(){
      //render是放在哪里的?——MyComponent的原型对象上,供实例使用
      //render中的this是谁?——MyComponent的实例对象/MyComponent组件实例对象
        return <h2>我是用类式定义的组件(适用于【复杂组件】的定义)</h2>
    }
  }
    //渲染组件到页面
  ReactDom.render(<MyComponent/>,document.getElementById('test'))
  /*
    执行ReactDom.render(<MyComponent/>,document......之后发生什么?
       1.React解析组件标签,找到MyComponent组件。
       2.发现组件是使用类定义的,随后new出了该类的实类,并通过该实例调用到原型上的render方法
       3.将render返回的虚拟DOM转化为真实DOM,随后呈现在页面中
  */
</script>

注意事项

  1. render()API要写在类的开头
  2. 类式组件定义的类需要继承React.Component类
  3. 创建的类不要new实例或者写构造器,因为继承的类都帮我们写好了

3.3、组件实例的三大核心属性

3.3.1、state(状态)

state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)。

组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)

案例:如图点击后改变天气

image
image
代码语言:javascript
复制
<script type="text/babel">
  //1.创建组件
  class Weather extends React.Component{
    constructor(props){//创建构造器
      super(props)
      //初始化状态
      this.state = {isHont:false} //state值一般转的是对象
    }
    render(){//重写父类的render()方法
      return <h1>今天天气很{this.state.isHont ? '炎热' : '凉爽'}</h1>
    }
    //2.渲染组件到页面
    ReactDOM.render(<Weather/>,document.getElementById('test'))
  }
</script>

上面的代码初始化了组件状态,通过判断isHont值就能判断返回炎热还是凉爽,现在我们只需要改变isHont值就可以完成上面的需求了,那如何改变isHont的值呢?

React中如何绑定事件 【复习】原生的三种事件绑定方法都可以进行事件判定,React官方推荐使用函数式绑定。类方法定义在类的原型对象上,供实例使用,通过类实例调用方法时,方法中的 this 指向的就是类实例。类中定义的方法在局部都开启了严格模式,直接调用不会指向window,所以值为undefined

React 不支持直接修改状态的属性,就算修改了React 本身也不作反馈

this.state. isHot = !isHot

需要借助setState这个API去更改

代码语言:javascript
复制
<script type="text/babel">
  //1.创建组件
  class Weather extends React.Component{
    constructor(props){//创建构造器
      super(props)
      //初始化状态
      this.state = {isHont:false}
      //解决changWeather中this指向问题
      this.changWeather=this.changWeather.bind(this)
    }
      render(){//重写父类的render()方法
      //读取状态
      const {isHot}=this.state
      return <h1 onClick={this.changWeather}>今天天气很{isHont ? '炎热' : '凉爽'}</h1>
    }
    changWeather(){
      //获取原来的isHot值
      const isHot=this.state.isHot
      //严重注意:状态必须通过setState进行更改,且更新是一种合并,并不是替换
      this.setState({isHot:!isHot});
    }
    //2.渲染组件到页面
    ReactDOM.render(<Weather/>,document.getElementById('test'))
  }
</script>

this.setState 这个API操作是合并操作,而不是替换。构造器只在new实例时调用,render在每次状态更新和初始化的时候调用,只要我们通过合法的方式(this.setState API)更新组件的状态,React会自己帮我们调用render方法更新组件

state 的简写方式 【复习】类中可以直接写赋值语句

代码语言:javascript
复制
<script type="text/babel">
  class Weather extends React.Component{
      //1.初始化状态
      state = {isHot:false,wind:'微风'}

      render(){
         const {isHot}=this.state
         return <h1 onClick={this.changWeather}>今天天气很{isHont ? '炎热' : '凉爽'}</h1>
    }
      //自定义方法——要用赋值语句的形式+箭头函数
      changWeather = ()=> {
        const isHot=this.state.isHot
        this.setState({isHot:!isHot});
      }
      ReactDOM.render(<Weather/>,document.getElementById('test'))
  }
</script>

【复习】箭头函数没有自己的this,所以他会往外部找this,所以函数里的this指向的其实Weather构造的实例对象

3.3.2、props

每个组件对象中对会含有props属性。组件标签的所有属性都保存在props中。通过标签属性从组件外向组件内传递变化的数据。组件内部不建议修改props的数据,数据的更新借助于state。

基本使用 需求: 自定义用来显示一个人员信息的组件

image
image
代码语言:javascript
复制
<script type="text/babel">
  //创建组件
  class Person extends React.Component{
    render(){
      console.log(this);
      const{name,age,sex}=this.props
        return(
        <ul>
           <li>姓名:{name}</li>
           <li>性别:{sex}</li>
           <li>年龄:{age}</li>
        </ul>
      )
    }
  }
  //渲染组件到页面
  ReactDOM.render(<Person name="Tom" sex="女" age="18">,document.getElementById('test1'))
  ReactDOM.render(<Person name="JACK" sex="男" age="17">,document.getElementById('test2'))
</script>

在渲染组件时传入值,React会直接将其存在props属性上,但考虑到一个问题,如果某个对象属性非常多这样写就不是很聪明

批量传递

代码语言:javascript
复制
<script type="text/babel">
  //创建组件
  class Person extends React.Component{
    render(){
      console.log(this);
      const{name,age,sex}=this.props
      return(
        <ul>
           <li>姓名:{name}</li>
           <li>性别:{sex}</li>
           <li>年龄:{age}</li>
        </ul>
      )
    }
  }
  const p={name:'老刘',age:18,sex:'女'}
  //渲染组件到页面
  ReactDOM.render(<Person {...p}>,document.getElementById('test2'))
</script>

对 props 进行限制 只有在Js原生的环境下我们才会谈数据类型,以及数据类型的判断,所以我们如果想传Number类型的数据到props时,要像下面这样写 ReactDOM.render(<Person age:{18}>,document.getElementById('test2'))

当我们的组件给别人使用时,别人不知道该往组件里传什么类型的属性,所以我们需要对props进行一些限制,React底层帮我们写好了我们需要按指定格式限制属性类型就可以了

代码语言:javascript
复制
Person.propTypes{
    name:React.PropTypes.string
}

这种方式已经在React 15.xxxx 版本时被弃用了,16.xxx 版本需要引入依赖包prop-types.js

它有什么用呢?—— 用于对组件标签属性进行限制,下好然后在项目中引用

代码语言:javascript
复制
Person.propTypes{
  name:PropTypes.string.isRequired,
  sex:PropTypes.string,
  age:PropTypes.number,
}
Person.defaultProps{
  sex:"男",
  age:18
}

Person.propTypes 对标签属性类型、必要性进行限制 语法:[属性名]:PropTypes.[数据类型].[必要性描述] 注意:数据类型都避开了原生的属性String、Number

Person.defaultProps 设置默认标签属性值

props 的简写方式 【注意】props是只读属性,只能get,不能set

代码语言:javascript
复制
<script type="text/babel">
  //创建组件
  class Person extends React.Component{
    static propTypes{
         name:PropTypes.string.isRequired,
         sex:PropTypes.string,
         age:PropTypes.number,
        }
    static defaultProps{
         sex:"男",
         age:18
        }
    render(){}}
</script type="text/babel">

关于类式构造器传不传props 类中构造器可写可不写,如果写了构造器constructor必调super函数,而构造中传不传props取决于你需不需要在构造器中通过this访问props,必接必传

数式组件使用 props

代码语言:javascript
复制
<script type="text/babel">
  //创建组件
  funciton Person(props){
    //限制标签类型和必要学
    return (
      <ul>
         <li>姓名:{name}</li>
         <li>性别:{sex}</li>
         <li>年龄:{age}</li>
      </ul>
    )
  }
    //函数式组件想使用限制器只能在外部设置
    Person.propTypes{
        name:PropTypes.string.isRequired,
        sex:PropTypes.string,
        age:PropTypes.number,
    }
    //默认值
    Person.defaultProps{
        sex:"男",
        age:18
    }
    //渲染组件到页面
    ReactDOM.render(<Person name='Tom' sex='男' age={18}/>,document.getElementById('test2'))
</script>

关于组件的三大核心属性,函数式组件只能使用props

3.3.3、refs

组件内的标签可以定义ref属性来标识自己。

字符串形式的ref

代码语言:javascript
复制
<script type="text/babel">
  class Demo extends.React.Component{
    showData()=>{
      const {input1}=this.refs
      alert(input1.value)
    }
    showData2 =()=>{
      const {input2}=this.refs
      alert(input2.value)
    }
   render(){
      return
      <div>
        <input ref="input1" type="text" placeholder="点击按钮提示数据"/>&nbsp;
        <button ref="button100" onClick={this.showData}>点我提示左侧数据</button>&nbsp;
        <input ref="input2" onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"/>&nbsp;
      </div>
    }
  }
</script>

组件里的标签可以通过ref属性来标识自己,然后都会收集到类实例的refs属性中,相当于原生中的id,但我们拿去值的方式也不原生中的document.getElementById,而是const{key值}=this.refs

【注意】 字符串的ref存在一些效率问题,如果写多了效率就不高,但方式简单,不过还是建议使用createRef API 和回调函数的ref

回调函数式的ref

代码语言:javascript
复制
<script type="text/babel">
  class Demo extends.React.Component{
    showData()=>{
      const {input1}=this.refs
      alert(input1.value)
    }
    showData2 =()=>{
      const {input2}=this.refs
      alert(input2.value)
    }
    render(){
      return
      <div>
        <input ref={a => this.input1=a} type="text" placeholder="点击按钮提示数据"/>&nbsp;
        <button onClick={this.showData}>点我提示左侧数据</button>&nbsp;
        <input ref={a => this.input2=a} onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"/>&nbsp;
      </div>
    }
  }
</script>

——关于回调函数的回调次数问题

在组件初始化的时候会执行一次,传入的是 DOM 元素

每次更新组件的时候都会调用两次回调函数,第一次传入值为null,第二次才传入参数DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,所以React 清空旧的 ref 并且设置新的。通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但大多数情况下它是无关紧要的

代码语言:javascript
复制
<script type="text/babel">
  class Demo extends.React.Component{
    saveInput=(c)=>
    {
      this.input=c;
      conosle.log('@',c);
    }
    render(){
      return
      <div>
        <input ref={this.saveInput} type="text" placeholder="点击按钮提示数据"/>&nbsp;
        <button onClick={this.showData}>点我提示左侧数据</button>&nbsp;
      </div>
    }
  }
</script>

createRef 的使用

代码语言:javascript
复制
<script type="text/babel">
  class Demo extends.React.Component{
     myRef=React.createRef()
     myRef2=React.createRef()

    //展示左侧输入框的数据
    showData =()=>{
        console.log(this.myRef.current.value);
    }

    //展示右侧输入框的数据
    showData2 =()=>{
        console.log(this.myRef2.current.value);
    }

    render(){
        return
      <div>
        <input ref={this.myRef} type="text" placeholder="点击按钮提示数据"/>&nbsp;
        <button onClick={this.showData}>点我提示左侧数据</button>&nbsp;
        <input ref={this.myRef2} onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"/>&nbsp;
      </div>
    }
  }
</script>

【注意】React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”的,只能存一个。这种方法繁琐的地方在于每次都要定义一个容器接受返回值,但也是官方最推荐的写法

四、收集表单数据

需求: 定义一个包含表单的组件,输入用户名密码后, 点击登录提示输入信息

4.1、非受控组件

代码语言:javascript
复制
<script type="text/babel">
    class Login extends React.Component{
      handleSubmit =(event)=>{//event 事件对象
        event.preventDefault()//阻止表单提交
        const {username,password}=this
        alert(`你输入的用户名是:{username.value} 密码是:{password}`)
    }
    render(){
      return (
        <form action="http://www.baidu.com" onSubmit={this.handleSubmit}>
         用户名: <input ref={c=>this.username=c}type="text" name="username"/>
         密码: <input ref={c=>this.password=c}type="password" name="password"/>
          <button>登录</button>
         </from>
      )
    }
    ReactDOM.render(<Login/>,document.getElementById('test'))
  }

</script>

非受控组件指的是,表单数据由DOM本身处理。即不受setState()的控制,与传统的HTML表单输入相似,input输入值即显示最新值。 在非受控组件中,可以使用一个ref来从DOM获得表单值。

非受控组件在底层实现时是在其内部维护了自己的状态state,这样表现出用户输入任何值都能反应到元素上。

4.2、受控组件

代码语言:javascript
复制
<script type="text/babel">
   class Login extends React.Component{
    handleSubmit =(event)=>{//event 事件对象
     demo=(exent)=>{
       this.setState({username:event.trage})
       conosle.log("@");
     }
    }
    render(){
      return (
         <form action="http://www.baidu.com" onSubmit={this.handleSubmit}>
         用户名: <input onChange={this.demo} type="text" name="username"/>
         密码: <input type="password" name="password"/>
          <button>登录</button>
         </from>
      )
    }
    ReactDOM.render(<Login/>,document.getElementById('test'))
  }

</script>

在HTML中,表单元素的标签<input>、<textarea>、<select>等的值改变通常是根据用户输入进行更新。

在React中,可变状态通常保存在组件的状态属性中,并且只能使用 setState() 进行更新,而呈现表单的React组件也控制着在后续用户输入时该表单中发生的情况,以这种由React控制的输入表单元素而改变其值的方式,称为受控组件。

比如,给表单元素input绑定一个onChange事件,当input状态发生变化时就会触发onChange事件,从而更新组件的state。

受控组件更新state的流程 1、 可以通过初始state中设置表单的默认值 2、每当表单的值发生变化时,调用onChange事件处理器 3、事件处理器通过事件对象event拿到改变后的状态,并更新组件的state 4、一旦通过setState方法更新state,就会触发视图的重新渲染,完成表单组件的更新

React中数据是单项流动的,从示例中,可以看出表单的数据来源于组件的state,并通过props传入,这也称为单向数据绑定。然后又通过onChange事件处理器将新的数据写回到state,完成了双向数据绑定。

4.3、总结

受控组件 受控组件依赖于状态 受控组件的修改会实时映射到状态值上,此时可以对输入的内容进行校验 受控组件只有继承React.Component才会有状态 受控组件必须要在表单上使用onChange事件来绑定对应的事件 非受控组件 非受控组件不受状态的控制 非受控组件获取数据就是相当于操作DOM 非受控组件可以很容易和第三方组件结合,更容易同时集成 React 和非 React 代码

两者使用场景 1、受控组件使用场景:一般用在需要动态设置其初始值的情况。例如:某些form表单信息编辑时,input表单元素需要初始显示服务器返回的某个值然后进行编辑。

2、非受控组件使用场景:一般用于无任何动态初始值信息的情况。例如:form表单创建信息时,input表单元素都没有初始值,需要用户输入的情况。

五、高阶函数_函数柯里化

5.1、高阶函数的定义

当一个函数符合下面两个规范中的任何一个,那该函数就是高阶函数

  • 接受的参数是一个函数
  • 调用的返回值依然是一个函数

例如:Promise、setTimeout、arr.mup() 等等

5.2、函数柯里化

函数柯里化:通过函数调用继续返回函数的方式,实现多次接受参数最后统一处理的函数编码形式,刚刚的saveFormData其实也用到了函数的柯里化,那么我们来简单演示一下你就明白了

5.3、案例分析

在开发中我们常常会遇到注册账号的需求。用户输入用户名、密码。

代码语言:javascript
复制
<script type="text/babel">
  class Login extends React.Component{//创建组件
      State={//初始化状态
        username='',//用户名
        password='',//密码
     }
     saveUsername=(exent)=>{//保存用户到状态中
        this.setState({username:event.target.value})
     }
     savePassword=(exent)=>{
        this.setState({password:event.target.value})
     }
     handleSubmit=(exent)=>{
        event.preventDefault()//阻止表单提交
        const{username,password}=this.state
        alert{`你输入的用户名是${username},你输入的密码是:${password}`}
     }
     render(){
        <from>
         用户名:<input onChange={this.saveUsername} type="text" name="username"/>
         密码:<input onChange={this.savePassword} type="password" name="password"/>
         <button>注册</button>
        </from>
     }
  }
</script>

这里可以看到saveUsername()和savePassword()这两条函数其实非常啰嗦,当需要保存的状态变多后不便于维护,如之后还要保存用户的身份证号、电话等信息。

【复习】对象的基本操作:在对象中想要拿到某个属性值名称需要使用 [ 属性名 ]

代码语言:javascript
复制
let a = 'name'
let obj={} //{name:obj}
obj[a]='tom'

我们使用高阶函数来重写编写刚刚的需求

代码语言:javascript
复制
<script type="text/babel">
  class Login extends React.Component{//创建组件
      state = {//初始化状态
      username='',//用户名
      password=''//密码
    }
    saveFormData=(dataType)=>{//保存表单数据到状态中
      return (event)=>{
      this.setState([dataType]:event.target.value)
      }
    }
    handleSubmit = (exent)=>{//表单提交的回调
      event.preventDefault()//阻止表单提交
      const{username,password}=this.state
      alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
    }
    render(){
        <from>
        用户名:<input onChange={this.saveFromData(username)} type="text" name="username"/>
        密码:<input onChange={this.saveFromData(password)} type="password" name="password"/>
        <button>注册</button>
      </from>
    }
  }
</script>

所谓函数柯里化是通过函数调用继续返回函数的方式,实现多次接受参数最后统一处理的函数编码形式,刚刚的saveFormData其实也用到了函数的柯里化,形式如下

代码语言:javascript
复制
function sum(a){
   return (b)=>{
    return (c)=>{
     return a+b+c;
     }
  }
}

const result = sum(1)(2)(3)

不使用柯里化的写法

代码语言:javascript
复制
<script type="text/babel">
  //创建组件
  class Login extends React.Component{
    //初始化状态
    state = {
      username='',//用户名
      password=''//密码
    }
    //保存表单数据到状态中
    saveFormData=(dataType,value)=>{
        this.setState([dataType]:value)
    }
    //表单提交的回调
    handleSubmit = (exent)=>{
      event.preventDefault()//阻止表单提交
      const{username,password}=this.state
      alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
    }
    render(){
        <from>
        用户名:<input onChange={event=>this.saveFromData('username',event)} type="text" name="username"/>
        密码:<input onChange={event=>this.saveFromData('password',event)} type="password" name="password"/>
        <button>注册</button>
      </from>
    }
  }
</script>
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-06-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、React 概述
    • 1.1、React 开发背景
      • 1.2、模块与组件、声明式与组件化
        • 1.3、虚拟DOM与真实DOM
        • 二、React 入门
          • 2.1、Hallo React
            • 2.2、JSX语法规则
              • 2.3、JS语句(代码)与JS表达式的区别
              • 三、面向组件编程
                • 3.1、函数式组件
                  • 3.2、类式组件
                    • 3.3、组件实例的三大核心属性
                      • 3.3.1、state(状态)
                      • 3.3.2、props
                      • 3.3.3、refs
                  • 四、收集表单数据
                    • 4.1、非受控组件
                      • 4.2、受控组件
                        • 4.3、总结
                        • 五、高阶函数_函数柯里化
                          • 5.1、高阶函数的定义
                            • 5.2、函数柯里化
                              • 5.3、案例分析
                              相关产品与服务
                              容器服务
                              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                              领券
                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档