react的特点:
1、声明式编码
2、组件化编码
3、React Native编写原生应用
4、高效(优秀的diff算法)
react高效的原因:
1、使用虚拟DOM,不总是直接操作页面真实DOM
2、使用DOM diff算法最小化页面重绘
react的基本使用
使用脚手架安装react项目:
1 | npm install -g create-react-app |
使用脚手架创建的react项目默认是不显示配置文件的,可以使用npm run eject 命令将配置文件显示出来,该命令一旦运行则无法再将配置文件隐藏。
jsx语法:
jsx语法是react定义的一种类似于XML的JS扩展语法,用来简化创建虚拟DOM,JS+XML本质是React.createElement(component,props,…children)方法的语法糖。可以在jsx中任意使用JavaScript表达式,不过需要包含在大括号中。
基本使用:
1 | //jsx语法 |
在代码编译之后可以看到JSX会被转化为普通的JS对象,所以实际上jsx语法返回的是一个JS对象,也称为React元素。在jsx中由于react DOM 在渲染之前默认会过滤掉所有传入的值,所有的内容在渲染之前都被转换为字符串,所以可以有效防止XSS(跨站脚本)攻击。
JSX的属性:
在jsx中可以使用引号来定义字符串属性,也可以使用大括号来定义JS表达式属性,如下所示:
1 | const ele = <h1 class="ele"></h1> |
更新元素渲染:
jsx语法返回的react元素时构成react应用的最小单位,在页面进行渲染,需要将react元素渲染到根DOM节点中,通过把它们传递给ReactDOM.render()方法来将其渲染到页面中。
1 | const ele = <h1 class="ele"></h1> |
由于react元素时不可变的,所以元素被创建之后更新页面的唯一办法就是创建一个新的元素然后传入ReactDOM.render()中替换掉之前的元素。
组件:
函数式组件:
1 | //1、创建函数式组件 |
执行了render函数之后,react会解析组件标签,发现组件时使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,最后呈现在页面中。
注意:组件的返回值只能有一个根元素,组件名称必须以大写字母开头,同时标签必须闭合。
类定义组件:
1 | //1、创建类式组件 |
执行了ReactDOM.render之后,发现组件时类定义的,react会new出来这个类的实例,并通过该实例调用到原型上的render方法,最后将render返回的虚拟DOM转为真实DOM,随后呈现在页面上。
组件传入值props:
当react元素时用户自定义的组件时,它会将JSX属性作为单个对象传递给组件,这个对象就是props,props的值只可以读取,不允许修改。如下图所示:
1 | //创建组件 |
组件局部状态state:
局部状态state用来维护内部数据,可以通过this.state.propName来获取数据。
组件可以将它的状态作为属性传递给子组件,但是除了拥有并设置它的组件之外,其他组件不可以访问其他组件的状态,这也是为什么叫做局部状态的原因。在修改局部状态时不要直接修改应该使用setState方法,否则react不会重新渲染组件。
setState方法只是将你的返回的对象合并到局部状态state中,并且是浅合并,即返回的对象中提及到的属性会被完全替换,没有涉及到的属性不受影响。
1 | this.setState({comment:"hello"}) |
在利用当前状态和props的值来修改下一状态时,应该用一个函数来作为setState的参数,否则如果直接修改的话,有可能会没有效果,因为这两种值是异步更新的。
1 | //错误做法 |
在实例对象中添加响应函数作为响应函数,响应函数会被放在实例的原型对象上供实例使用。比如当我们在jsx语法中为一个标签添加点击事件响应函数handleClick,该函数是作为OnClick的回调。所以不是通过实例调用的,是直接调用,由于类中的方法默认开启了局部的严格模式,所以handleClick中的this是undefined,无法获取到实例的state属性。
可以在类构造器中使用this.handleClick = this.handleClick.bind(this)将this绑定为实例后放到实例对象身上,这样当点击时响应函数就是实例上的handleClick函数,而不是原型对象上的handleClick函数。
state的简写方式:
可以不需要在类的构造器中,而是直接在类中初始化state,自定义方法也可以不需要在构造器中手动绑定this,而是将自定义方法在类中用赋值语句+箭头函数的形式声明即可,此时this指向的就是类的实例。
1 | class Weather extends React.Component { |
refs:
refs提供了一种方式,允许我们访问DOM节点或在render方法中创建的react元素。
创建refs:
refs是使用Reat.createRef()创建的,并通过ref属性附加到React元素,在构造组件时通常将refs分配给实例属性以便可在整个组件中引用它们。
当ref被传递给render中的元素时,对该节点的引用可以在ref的current属性中访问
1 | const node = this.myRef.current |
ref的值根据节点的类型有所不同:
- 当ref属性用于HTML元素时,构造函数中使用React.createRef()创建的ref接收底层的DOM元素作为current属性
- 当ref属性用于自定义class组件时,ref对象接收组件的挂载实例作为其current属性
1 | //为DOM元素添加ref |
react的生命周期:
生命周期函数(旧):
1、初始化阶段:由React.render()触发 –初次渲染,调用顺序是
- constructor()
- componentWillMount()
- render()
- componentDidMount()
2、更新阶段:由组件内部this.setState()或父组件render触发,调用顺序是:
- shouldComponentUpdate():通过返回值控制组件更新的“阀门”
- componentWillUpdate()
- render()
- componenrDidUpdate()
3.、卸载组件:由ReactDOM.unmountComponentAtNode()触发
- componentWillUnmount() –常用,一般在这个钩子中做一些收尾的事,比如关闭定时器,取消消息订阅等。
生命周期函数(新):
1、初始化阶段:由React.render()触发 –初次渲染,调用顺序是
- constructor()
- getDerivedStateFromProps
- render()
- componentDidMount()
2、更新阶段:由组件内部this.setState()或父组件render触发,调用顺序是:
getDerivedStateFromProps
shouldComponentUpdate():通过返回值控制组件更新的“阀门”
render()
getSnapshotBeforeUpdate()
componenrDidUpdate()
3.、卸载组件:由ReactDOM.unmountComponentAtNode()触发
- componentWillUnmount() –常用,一般在这个钩子中做一些收尾的事,比如关闭定时器,取消消息订阅等。
事件处理:
1、通过onXXX属性指定事件处理函数(注意大小写)
- react使用的是自定义事件,而不是使用的原生DOM事件
- react中的事件是通过事件委托方式处理的
2、通过event.target得到发生事件的DOM元素对象
3、在react中不能使用返回false的方式阻止默认行为,必须明确使用preventDefault
给事件传递参数:
1、箭头函数
1 | <button onClick = {(e) => this.deleteRow(id,e)}>Delete Row</button> |
2、bind函数
1 | //通过bind方式向监听对监听对象传参,在类组件中定义的监听对象,事件对象e要排在所传递的参数后面 |
条件渲染
1 | //if语句控制是否渲染 |
如果不想让组件渲染可以让render返回null,组件的render方法返回null并不会影响该组件生命周期方法的回调。
列表渲染
1 | function NumberList(props){ |
react在列表渲染的时候必须给每个列表元素分配一个唯一的key值,否则会出现警告。
表单元素
受控组件:使用受控组件可以将用户输入的值保存在组件的状态属性中,并且能控制用户输入时所发生的变化
1 | class NameForm extends React.Component { |
非受控组件:指表单数据不受React控制,而是由DOM节点自己控制。
高阶函数与函数柯里化
高阶函数:如果一个函数符合下面2个规范中的任何一个就是高阶函数。
1、若A函数,接收的参数是一个函数,那么A就是高阶函数
2、若A函数,调用的返回值依然是一个函数,那么A就可以称为高阶函数
函数柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式
状态提升
在react中将多个组件中需要共享的state向上移动到它们共同的父组件中,便可实现共享state。
在react应用中,任何可变数据应当只有一个相对应的唯一数据源。通常,state都是首先添加到渲染数据的组件中去,如果其他组件需要这个state就需要提升到共同组件中,然后使用props进行父子组件传值,当需要在子组件中修改父组件的值时,此时需要再通过props调用父组件自身的方法修改,不能直接使用子组件对props的数据进行修改。