React概述
react是什么?
React用于构建用户界面的JS库。是一个将数据渲染为HTML视图的开源JS库。
为什么学?
1.原生JS操作DOM繁琐,效率低
2.使用JS直接操作DOM,浏览器会进行大量的重绘重排
3.原生JS没有组件化编码方案,代码复用低
在学习之前最好看一下关于npm的知识:下面是我在网上看见的一个写的还不错的npm的文章
npm
React的特点
1.组件化开发,声明式编码,提高效率
- 组件化开发:把复杂的代码,拆成一块一块组件,模块化开发
- 声明式编码:比如我写了一个页面,页面上有一个蓝色的图形,我想改这个图形的颜色,我只需要通过改某个命令或者传入的某个参数就可以实现颜色的修改,不需要去修改这个页面代码,这便是声明式编码
2.在React Native中,使用React进行移动端开发
3.使用虚拟DOM+Diffing算法,减少真实DOM操作,大大提升效率
- 虚拟DOM,是一种空间换时间的做法,数据先到虚拟DOM上,再通过虚拟DOM映射到真实DOM上,这种做法只有第一次页面加载时会稍慢一些(因为加了一层虚拟DOM到真实DOM的映射)。但是在后续数据变更,DOM修改的时候,就会明显体现优势。以前DOM更新操作只会去更新全体数据区域,消耗极大,而虚拟DOM在更新前会进行比对(Diffing算法),只更新需要更新的内容,减少新建开销,从而优化性能
以H5+JS引入的原生方式开始React
依赖导入
既然是原生H5,那么就要用script
标签引入React的js依赖
介绍一下需要的js依赖,这三个是非常基础的库,而且一定要按图上固定的顺序导入
最后引入babel标签,告诉编译器,这里需要去从JSX转换成JS
注意:<script type="text/babel">
如果类型写错了,会发生错误,导致浏览器不认识标签,因为JS中根本没有标签这一说
控制台信息
正常运行控制台会提示的信息
代码
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello React!</title>
<meta charset="UTF-8">
<!-- 动态适配 -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="css/style.css" rel="stylesheet">
</head>
<body>
<div id="test"></div><!--真实DOM-->
<script type="text/javascript" src="../js/react.development.js"></script> <!--React核心的库-->
<script type="text/javascript" src="../js/react-dom.development.js"></script><!--React操作Dom相关库-->
<script type="text/javascript" src="../js/babel.min.js"></script><!--将JSX转换成JS用的依赖,因为浏览器不认识JSX,只认识JS-->
<!-- 最后引入babel标签,这里是告诉编译器这里是JSX,需要用babel转换成JS文件
如果不小心写成其他的类型,那么浏览器就无法编译通过 -->
<script type="text/babel">
// 虚拟DOM创建
const virDom=<h1>hello React</h1>
// 将虚拟DOM渲染到某个指定的真实DOM上面
ReactDOM.render(virDom,document.getElementById("test"))
</script>
</body>
</html>
用JS和JSX分别创建虚拟DOM
前置条件依旧是引入上面的三个依赖
用JS创建虚拟DOM
其实JS也可以做成类似于JSX的写法
首先回顾一下
传统创建真实DOM元素,可以通过操作document对象来进行创建
document.createElement("div")
而我们创建虚拟DOM,因为我们引入了React依赖,所以就可以通过React对象创建虚拟DOM。注意,即使是JS创建,也不可以想当然的用双引号把元素括起来,因为React不认识这种写法
React.createElement("标签名","标签属性","标签内容")
例子:
const virDom=React.createElement("h1",{id:'title'},'这是内容')
这样我们就通过JS创建了一个虚拟DOM元素,但是这种创建方式创建单层元素还好,一旦创建很多元素就会非常麻烦
比如我要在DIV里面套一个span(span没属性)就得这样:
const virDom=React.createElement("h1",{id:'title'}, React.createElement("span",{},'这是span内容'))
如果元素过多就得层层套娃,非常痛苦
最后渲染指定真实DOM即可,注意这里就有意思了,因为是JS创建的,所以标签类型指定了JS,而不是Babel
<script type="text/javascript">
const virDom=React.createElement("h1",{id:'title'}, React.createElement("span",{},'这是span内容'))
// 虚拟DOM创建
// 将虚拟DOM渲染到某个指定的真实DOM上面
ReactDOM.render(virDom,document.getElementById("test"))
</script>
测试肯定好用,就不演示了
但这样非常麻烦,一个元素就快累疯了,所以引入了JSX
用JSX创建虚拟DOM
此时用JSX就非常容易标签套娃了
const定义的时候套一层括号代表是一个整体,写完标签,渲染到真实DOM上就可以了
<script type="text/babel">
// 虚拟DOM创建,JSX开始套娃
const virDom=(
<h1>
<h2>
<div>123</div>
</h2>
</h1>
)
// 将虚拟DOM渲染到某个指定的真实DOM上面
ReactDOM.render(virDom,document.getElementById("test"))
</script>
这里需要注意,因为JSX是JS+XML,所以如果不是单纯的标签语言,混入了一些JS,那么一定要用{}
把JS代码括起来
const virDom=(
<div>
<h1>前端js框架列表</h1>
<ul>
{
data.map((item,index)=>{
return <li key={index}>{item}</li>
})
}
</ul>
</div>
)
JSX—>JS原理
所以到这里,大概就可以才出来babel的原理了
通过babel把写好的JSX,一层一层标签去挨个套娃转换,最终转换成这种React.createElement的JS创建形式。
const virDom=React.createElement("h1",{id:'title'}, React.createElement("span",{},React.createElement(...n层标签)))
这也就是为什么前面控制台说,不建议用生产环境用Babel转换,这种转换的方式标签少的话还好,如果大量去现场从JSX转换成JS,那么会非常耗时,用户一进来看见一个白画面(等待从JSX转换成JS),这是很不友好的。后面开发时会替代这种写法。
虚拟DOM和真实DOM比较
关于虚拟DOM,本质就是Object,即为一般对象,所以相对于一个真实的DOM来说,更轻。
虚拟DOM是React内部在处理,无需真实DOM上的那么多属性。
但最后虚拟DOM还是会被转化为真实DOM,最后呈现在画面上。
真实DOM具有很多的属性
JSX语法
定义JSX的时候不要写引号
JSX在创建虚拟DOM的时候,不可以用字符串引号创建,会导致无法识别
标签中混入JS表达式的时候要用{}
在JSX中,想用JS必须要用{}
套一下,套完代码就会被认为是JS代码
比如给一个div标签设置id,利用{}
进行读取
运行代码,则可以发现读取成功
样式类名
注意,React标签中,没有class属性,因为如果写了class就与ES6的语法相冲突,所以这里的class属性改名为className
如果React代码里写了class,就会被控制台提示是否是写错了
注意,class属性的话,是不需要去用{}
进行插值的,这属于原生的代码
例子
在title属性中,定义一个css样式,准备在后面标签引用
在标签中直接以字符串的形式进行样式引用
样式生效
但是此时会被报错,也就是要改为className标记样式
改为className就没有报错了
内联样式
所谓内联样式就是在标签上面直接标出css、
例子: <span className = "sss" style = {{fontSize:'50px'; color:'origin'}}>
React中如果使用内联样式,则需要去用{{样式属性}}
标记,注意是两层花括号
- 外层花括号代表在JSX中引用JS
- 内层花括号代表一个JS对象(对象里描述了样式)
则语法为:style={{key1:'value1' , key2:'value2'}}
只有一个根标签
这个不用多赘述,定义的那个虚拟DOM只保持一个根标签,图上多个就报错了
标签必须闭合
无论是单个或者多个标签,JSX中必须保持闭合
单个标签不闭合报错
闭合了即正确(2选1均可)
单标签闭合
双标签闭合
标签首字母
小写字母开头
就将标签转化为html同名元素,如果html中无该标签对应的元素,就报错;
随便定义一个标签
大写字母开头
react就去渲染对应的组件,如果没有就报错
直接认为是React标签,在React组件中找不到定义,则直接报错
JSX小练习
JS表达式和JS语句的区别
关于JS表达式和JS语句分别是什么:
JS表达式:返回一个值,可以放在任何一个需要值的地方 a a+b demo(a) arr.map() function text(){}
JS语句:if(){} for(){} while(){} swith(){} 不会返回一个值
这二者如何区分呢?
就是用 一个变量去接这个代码,看看有没有返回值
- 有返回值的就是JS表达式
- 没有返回值的就是语句(条件判断语句, 转向语句,循环执行语句…)
为什么要说这个?
是因为,标签中混入JS表达式的时候要用{}
换句话说:
就是,{}
中只能放入JS表达式
举例
放入JS表达式,可能有返回值,可以放入
放入JS语句,没有返回值,报错
用JSX循环显示数组
渲染出来的效果
但是控制台会有报错
意思这种循环出来的标签,需要有自己的unique key,因为diffing算法需要用这个key,所以这里报错
稍加修改,用遍历时自动生成的index作为unique key,但是这种做法会有问题,但是这里先不用处理,后续学习中会说明