课程原视频: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

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

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

关于虚拟DOM

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

二、React 入门

准备工作

1.创建项目文件

2.下载依赖包

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

3.引入依赖包

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

<! -- 引入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

开始写代码

<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

运行效果

2.2、JSX语法规则

在React 中的语法是JSX 并不是JS 有一定区别。

①:定义虚拟DOM时,不要使用引号

const VDOM = (
<h2 id="myId">
<span>myData</span>
</h2>
)

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

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

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

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

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

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

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

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

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

⑤:只有一个根标签

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

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语法小练习

需求: 动态展示如下列表

//模拟一些数据
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表达式的区别

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

 (1). a
(2). a+b
(3). demo(1)
(4). arr.map()
(5). function test () {}

语句(代码):

 (1) . if() {}
(2) . for() {}
(3) . swich() {case:xxxx}

React 接收到数组数据时会自动帮我们遍历,如果传的是对象会报错

Object are not valid as a React child

三、面向组件编程

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

3.1、函数式组件

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

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

<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. 类中所定义的方法,都放在了类的原型对象上,供实例去使用
<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来更新对应的页面显示(重新渲染组件)

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

<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去更改

<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 的简写方式

【复习】类中可以直接写赋值语句

<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。

基本使用

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

<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属性上,但考虑到一个问题,如果某个对象属性非常多这样写就不是很聪明

批量传递

<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底层帮我们写好了我们需要按指定格式限制属性类型就可以了

Person.propTypes{
name:React.PropTypes.string
}

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

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

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

<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

<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

<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

<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 的绑定函数的方式可以避免上述问题,但大多数情况下它是无关紧要的

<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 的使用

<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、非受控组件

<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、受控组件

<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、案例分析

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

<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()这两条函数其实非常啰嗦,当需要保存的状态变多后不便于维护,如之后还要保存用户的身份证号、电话等信息。

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

let a = 'name'
let obj={} //{name:obj}
obj[a]='tom'

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

<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其实也用到了函数的柯里化,形式如下

function sum(a){
return (b)=>{
return (c)=>{
return a+b+c;
}
}
} const result = sum(1)(2)(3)

不使用柯里化的写法

<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>

最新文章

  1. Session在类库中的使用
  2. Easyui的渲染
  3. JAVA作业02
  4. 天使之城(codevs 2821)
  5. [linux basic 基础]----同步信号量
  6. js-布尔值
  7. Java Applet与Java Application的特点
  8. hdu 4920 Matrix multiplication (矩阵计算)
  9. CH BR8(小学生放假了-clock()/CLOCKS_PER_SEC-斜率优化常错集锦)
  10. CQRS(命令查询职责分离)和 EDA(事件驱动架构)
  11. &gt;&gt; 计算机的数据表示
  12. 卷积神经网络(CNN)反向传播算法
  13. 超级简单实用的前端必备技能-javascript-全屏滚动插件
  14. Android Studio Termanal打不开,提示java.io.IOEXception:couldn&#39;t create PTY
  15. ubuntu 16.04 LTS - 谷歌拼音输入法
  16. Linux系统初始化配置项(centos7)
  17. dubbo系列六、SPI扩展Filter隐式传参
  18. mysql 设置用户并授权
  19. @Transactional注解事务不回滚不起作用无效
  20. vuex - 辅助函数学习

热门文章

  1. 客户流失?来看看大厂如何基于spark+机器学习构建千万数据规模上的用户留存模型 ⛵
  2. Java-面向对象三大特征、设计规则
  3. centos7.6内核之cfs_bandwidth下的distribute_cfs_runtime hard lockup
  4. 轻量级消息队列 Django-Q 轻度体验
  5. 抛砖系列之git仓库拆分工具git-filter-repo
  6. KingbaseESV8R6 垃圾回收原理以及如何预防膨胀
  7. Java 多线程:基础
  8. yum install lrzsz
  9. Python数据科学手册-Numpy数组的计算:比较、掩码和布尔逻辑,花哨的索引
  10. 第六章:Django 综合篇 - 15:Django与缓存