React全家桶:React基础、React-Router路由、PubSub消息管理、Redux集中式状态管理、Ant-Design一个UI组件库。
一、React入门
1、React是什么?
React是用于构建用户界面的JavaScript库。操作DOM呈现页面。是一个将数据渲染成HTML视图的开源JavaScript库。
2、React由Facebook开发开源的
3、为什么学React
原生JavaScript操作DOM繁琐、效率低(DOM-API操作UI)。使用JavaScript直接操作DOM,浏览器会进行大量的重绘重排。原生JavaScript没有组件化编码方法,代码复用率低。
4、React的特点
1、采用组件化模式,声明式编码,提高开发效率及组件复用率。
2、在React Native中可以使用React语法进行移动端开发。
3、使用虚拟DOM+优秀的Diffing算法,尽量减少与真实DOM的交互。
5、React为什么高效
使用虚拟DOM,不总是直接操作页面真实DOM,DOM Diffing算法,最小化页面重绘
6、学习React之前要掌握的JavaScript基础
判断this的指向、class(类)、ES6语法规范、npm包管理器、原型、原型链、数组常用方法、模块化
7、React的基本使用
(1)React的相关js库
1、react.js:React核心库
2、react-dom.js:提供操作DOM的react扩展库
3、babel.min.js:解析jsx语法代码转化为js代码的库
(2)创建虚拟DOM的两种方法
1、纯js方式(一般不用)
2、jsx方式
(3)虚拟DOM和真实DOM
1、React提供了一些API来创建一种“特别”的一般js对象
/* 创建一个简单的虚拟DOM对象 */ const VDOM = React.createElement('xx',{id:'xx'},'xx')
2、虚拟DOM对象最终都会被React转换为真实的DOM
3、编程时只需要操作react的虚拟DOM的相关数据,react会转换为真实DOM变化而更新姐面
4、虚拟DOM本质就是Object类型的对象。虚拟DOM比较“轻”(属性少),真实DOM比较“重”(属性多)。虚拟DOM是React内部在用,无需真实DOM上那么多的属性。
5、虚拟DOM会被React转换成真实DOM,呈现在页面上。
(4)React JSX
XML:早期用于存储和传输。
全称:JavaScript XML
- react定义的一种类似于XML的JS扩展语法: JS + XML本质是React.createElement(component, props, ...children)方法的语法糖
- 作用: 用来简化创建虚拟DOM
- 写法:var ele = <h1>Hello JSX!</h1>
- 注意1:它不是字符串, 也不是HTML/XML标签
- 注意2:它最终产生的就是一个JS对象
- 标签名任意: HTML标签或其它标签
- 标签属性任意: HTML标签属性或其它
- 基本语法规则
- 遇到 <开头的代码, 以标签的语法解析: html同名标签转换为html同名元素, 其它标签需要特别解析
- 遇到以 { 开头的代码,以JS语法解析: 标签中的js表达式必须用{ }包含
- babel.js的作用
- 浏览器不能直接解析JSX代码, 需要babel转译为纯JS的代码才能运行
- 只要用了JSX,都要加上type="text/babel", 声明需要babel来处理
jsx语法规则:
1、定义虚拟DOM,不要写引号。
2、标签中混入js表达式时,用{}包裹。
3、标签中有多个属性时,用空格隔开。
4、标签中有多个子元素时,用逗号隔开。
5、jsx语法编译成js代码时,会自动调用React.createElement()方法。
6、样式的类名指定时,用className属性,而不是class。
7、根标签只能有一个,不能有多个。
8、内联样式要用style={{key:value}}包裹。
9、标签必须闭合。
10、标签首字母:
(1)小写字母开头,则将该标签转为HTML中的同名标签,若HTML中没有同名标签,则会报错。
(2)大写字母开头,React就去渲染对应的组件,若没有定义该组件,则会报错。
(5)渲染虚拟DOM(元素)
- 语法: ReactDOM.render(virtualDOM, containerDOM)
- 作用: 将虚拟DOM元素渲染到页面中的真实容器DOM中显示
- 参数说明
- 参数一: 纯js或jsx创建的虚拟dom对象
- 参数二: 用来包含虚拟DOM元素的真实dom元素对象(一般是一个div)
8、模块与组件、模块化与组件化的理解
(1)模块
- 理解:向外提供特定功能的js程序, 一般就是一个js文件
- 为什么要拆成模块:随着业务逻辑增加,代码越来越多且复杂。
- 作用:复用js, 简化js的编写, 提高js运行效率
(2)组件
- 理解:用来实现局部功能效果的代码和资源的集合(html/css/js/image等等)
- 为什么要用组件: 一个界面的功能更复杂
- 作用:复用编码, 简化项目编码, 提高运行效率
(3)模块化
当应用的js都以模块来编写的,这个应用就是一个模块的应用
(4)组件化
当应用是以多组件的方式实现, 这个应用就是一个组件化的应用
二、React面向组件编程
1、组件
(1)函数式组件
函数式组件:使用函数编写组件。
类式组件:使用类编写组件。
类的基础知识回顾:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>1、类的基础知识复习</title>
</head>
<body>
<script type="text/javascript">
//定义一个Person类
class Person {
//构造器函数
constructor(name, age) {
this.name = name
this.age = age
}
//一般方法
sayHello() {
//sayHello方法放在了类的原型对象上,所以可以直接通过实例对象调用
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
//创建一个student类,继承Person类
class Student extends Person {
//构造器函数
constructor(name, age, grade) {
super(name, age)
this.grade = grade
}
//重写父类的sayHello方法
sayHello() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old, I am in grade ${this.grade}.`);
}
}
//实例化Student类
const student1 = new Student('Jerry', 18, 3);
console.log(student1); //输出Jerry
student1.sayHello(); //输出Hello, my name is Jerry and I am 18 years old, I am in grade 3.
//实例化Person类
const person1 = new Person('Tom',20);
console.log(person1); //输出Tom
person1.sayHello(); //输出Hello, my name is Tom and I am 20 years old.
</script>
</body>
</html>
(2)类式组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>类式组件</title>
<!-- 引入React -->
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!-- 引入Babel -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<!-- 定义一个div作为渲染的目标 -->
<div id="root"></div>
<script type="text/babel">
// 定义一个类式组件
class Hello extends React.Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
// 渲染组件
ReactDOM.render(
<Hello name="World" />,
document.getElementById('root')
);
</script>
</body>
</html>
复杂组件与简单组件的区分:
有状态(state)的是复杂组件,没有状态(state)的是简单组件
(3)状态state
组件实例的三大属性之一。
- state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)
- 组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)
- 组件中render方法中的this为组件实例对象
- 组件自定义的方法中this为undefined,如何解决?
- 强制绑定this: 通过函数对象的bind()
- 箭头函数
- 状态数据,不能直接修改或更新
<script type="text/babel">
//1.创建组件
class Weather extends React.Component{
//初始化状态
state = {isHot:false,wind:'微风'}
render(){
const {isHot,wind} = this.state
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
}
//自定义方法————要用赋值语句的形式+箭头函数
changeWeather = ()=>{
const isHot = this.state.isHot
this.setState({isHot:!isHot})
}
}
//2.渲染组件到页面
ReactDOM.render(<Weather/>,document.getElementById('test'))
<script type="text/babel">
//1.创建组件
class Weather extends React.Component{
//构造器调用几次? ———— 1次
constructor(props){
console.log('constructor');
super(props)
//初始化状态
this.state = {isHot:false,wind:'微风'}
//解决changeWeather中this指向问题
this.changeWeather = this.changeWeather.bind(this)
}
//render调用几次? ———— 1+n次 1是初始化的那次 n是状态更新的次数
render(){
console.log('render');
//读取状态
const {isHot,wind} = this.state
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
}
//changeWeather调用几次? ———— 点几次调几次
changeWeather(){
//changeWeather放在哪里? ———— Weather的原型对象上,供实例使用
//由于changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用
//类中的方法默认开启了局部的严格模式,所以changeWeather中的this为undefined
console.log('changeWeather');
//获取原来的isHot值
const isHot = this.state.isHot
//严重注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。
this.setState({isHot:!isHot})
console.log(this);
//严重注意:状态(state)不可直接更改,下面这行就是直接更改!!!
//this.state.isHot = !isHot //这是错误的写法
}
}
//2.渲染组件到页面
ReactDOM.render(<Weather/>,document.getElementById('test'))
</script>
(4)props:传值
理解
- 每个组件对象都会有props(properties的简写)属性
- 组件标签的所有属性都保存在props中
作用
- 通过标签属性从组件外向组件内传递变化的数据
- 注意: 组件内部不要修改props数据
编码操作
1.内部读取某个属性值
2.对props中的属性值进行类型限制和必要性限制
3.扩展属性:将对象的所有属性通过props传递
4.默认属性值
5.组件类的构造函数
什么是props
props 用于组件的传值,他的工作就是为了接受外面传过来的数据,是一个配置项,与data、el、ref 是一个级别的。
props的使用:
(1)静态props
静态即传入的值不变化,直接在父组件中定义,子组件中使用。
(2)动态props
动态即传入的值会变化,父组件中要动态地绑定父组件的数据。
(3)props验证
验证传入的props参数的数据规格,如果不符合数据规格则发出警告,注意这个数据类型包含所有的数据类型,如基本类型和引用类型;还可以在验证中加入自定义验证函数,当返回false时则发出警告。
<script type="text/babel">
//创建组件
class Person extends React.Component{
render(){
// console.log(this);
const {name,age,sex} = this.props
//props是只读的
//this.props.name = 'jack' //此行代码会报错,因为props是只读的
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age+1}</li>
</ul>
)
}
}
//对标签属性进行类型、必要性的限制
Person.propTypes = {
name:PropTypes.string.isRequired, //限制name必传,且为字符串
sex:PropTypes.string,//限制sex为字符串
age:PropTypes.number,//限制age为数值
speak:PropTypes.func,//限制speak为函数
}
//指定默认标签属性值
Person.defaultProps = {
sex:'男',//sex默认值为男
age:18 //age默认值为18
}
//渲染组件到页面
ReactDOM.render(<Person name={100} speak={speak}/>,document.getElementById('test1'))
ReactDOM.render(<Person name="tom" age={18} sex="女"/>,document.getElementById('test2'))
const p = {name:'老刘',age:18,sex:'女'}
// console.log('@',...p);
// ReactDOM.render(<Person name={p.name} age={p.age} sex={p.sex}/>,document.getElementById('test3'))
ReactDOM.render(<Person {...p}/>,document.getElementById('test3'))
function speak(){
console.log('我说话了');
}
</script>
(5)refs与事件处理
对refs的理解:
组件中的标签可以定义refs属性来标识自己
refs属性编码:
字符串形式的ref
<input ref="input1" />
回调形式的ref
<input ref={(c)=>{this.input1 = c}} />
createRef创建ref容器
myRef = React.createRef() <input ref={this.myRef} />
(6)事件处理:
事件处理:
通过onXxx属性指定事件处理函数(区分大小写)
React使用的是自定义(合成)事件,而不是原生DOM事件
React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)
通过event.target得到发生事件的DOM元素对象
收集表单数据
包含表单的组件分类:受控组件和非受控组件
组件的生命周期
对生命周期的理解:
1、组件从创建到死亡的一些特定的阶段
2、React组件中包含一系列勾子函数(生命周期回调函数),会在特定的时刻回调
3、定义组件时,在特定的生命周期回调函数中,做特定的工作
/* 重要的勾子 */
render //初始化渲染或更新渲染调用
componetDidMount //开启监听,发送ajax请求
componentWillUnmount //完成收尾工作,如:清空定时器
React脚手架项目结构:
public ---- 静态资源文件夹
favicon.icon ------ 网站页签图标
index.html -------- 主页面
logo192.png ------- logo图
logo512.png ------- logo图
manifest.json ----- 应用加壳的配置文件
robots.txt -------- 爬虫协议文件
src ---- 源码文件夹
App.css -------- App组件的样式
App.js --------- App组件
App.test.js ---- 用于给App做测试
index.css ------ 样式
index.js ------- 入口文件
logo.svg ------- logo图
reportWebVitals.js--- 页面性能分析文件(需要web-vitals库的支持)
setupTests.js---- 组件单元测试的文件(需要jest-dom库的支持)
React ajax
理解:
React本身只关注界面,并不包含发送ajax请求的代码
前端应用需要通过ajax请求与后台进行交互(json数据)
React应用中需要集成第三方ajax库(自己封装)
常用的ajax请求库
1、jQuery:比较重
2、axios:轻量级
(1)封装XmlHttpRequest对象的ajax
(2)promise风格
(3)可以用在浏览器端和node服务器端
React路由
理解:
一、对SPA的理解:
1、单页Web应用(single page web application,SPA)
2、整个应用只有一个完整的页面
3、点击页面中的链接,不会刷新页面,只会做页面的局部更新
4、数据需要通过ajax请求获取,并在前端异步展现
二、对路由的理解:
1、什么是路由?
(1)一个路由就是一个映射关系(key:value)
(2)key为路径,value可能是函数(funcation)或者组件(component)
2、路由的分类:
(1)后端路由
<1>理解:value是funcation,用来处理客户端提出的请求
<2>注册路由:router.target(path,funcation(req,res))
<3>工作过程:当node收到一个请求时,根据请求路径找到匹配的路由,调用路
由中的函数处理请求,返回响应数据
(2)前端路由
<1>浏览器端路由,value是component,用于展示页面内容
<2>注册路由:<Route path="/test" component={Test}>
<3>工作过程:当浏览器的path变为/test时,当前路由组件就会变成Test组件
react-router-dom
对react-router-dom的理解:
1、react的一个插件库
2、实现SPA应用
3、基于React的项目都会用到这个库
react-router-dom相关API
/* 内置插件 */
<BrowserRouter>
<HashRouter>
<Route>
<Redirect>
<Link>
<NavLink>
<Switch>
1、history对象
2、match对象
3、withRouter函数
基本路由使用:
准备工作:
1、下载react-router-dom:
npm install --save react-router-dom
2、引入bootstrap.css:
2.<link rel="stylesheet" href="/css/bootstrap.css">