在学习基础知识之前,我们可以在本地搭建并运行一个react应用,便于后续学习时例子效果预览。请先确保电脑已成功安装node.js
。
比如我的学习项目都喜欢丢在D盘,所以可以在D盘新建一个job文件夹(名字随你喜欢),进入job目录,打开终端,这里我用的git终端。执行复制npx create-react-app my-app
命令并回车,等待安装完成。
等到出现Happy hacking!,说明下载完成。
之后就可以看到job目录下多了一个my-app
文件夹,这就是我们下载的react应用了。双击进入my-app目录,再进入src文件夹,删除所有文件之后,创建index.css与index.js文件,像这样:
用编辑器(我用的vscode)打开my-app项目,在前面创建的index.js中拷贝如下代码:
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
ReactDOM.render(<h1>Hello, world!</h1>, document.getElementById("root"));
注意,由于react的jsx语法特性,我们可以在js中编写html,所以习惯格式化代码的同学可能会将代码格式出问题,毕竟js中无法识别HTML。对于这个问题我们可以通过切换编辑器语言模式来解决,点击编辑器右下角的语言,如下图:
输入java
可以看到下方有个javaScript React
,选择此语言,再格式化你就发现支持jsx语法了。
每次点击右下角切换语言也比较麻烦,好的做法是给选择语言模式直接配置一个键盘快捷方式。点击编辑器左上角的文件--->首选项--->键盘快捷方式,之后输入语言
,可以看到有一个更改语言模式。点击左边的修改图标,输入你想要的快捷方式,保存即可,这里我用快捷键是ctrl+k
,之后就可以通过快捷键快速切换语言模式了。
ok,简单说了下语言模式的事情,现在我们可以通过ctrl+~
打开编辑器的终端,然后输入npm start
并回车。
你会发现浏览器自动打开了一个页面,这就是我们本地开发环境成功跑起来了。使用本地环境的好处是,我们每次修改并保存代码,页面都会自动刷新,而此时页面赫然显示了一句 Hello, world!,恭喜你,到这里我们成功创建了第一个属于自己的应用,虽然它目前还很简单,但通过后面的学习,我们来一起让它变得更酷!
按照以往传统的开发习惯,dom结构我们一般写在html中,而js文件会负责业务相关逻辑,但站在react的角度,我们会在js中编写html相关代码,如果你有了解vue的jsx语法,我想你会更快接受这一设定,之前没了解也不用担心,我们来解释下文章开头代码做了什么。
让我们打开项目的public文件,查看index.html
,可以看到代码中有一个id为root
的div盒子,结合我们前面例子中ReactDOM.render
编译的内容,其实不难理解,render
只是将需要编译的dom,塞到了root
的盒子中,这种指定应用容器以及编译内容的思想其实与vue以及angularjs是相似的,只是现在html换了个地方编写而已。
jsx属于JavaScript的语法拓展,事实上它既不是标签语法,也不是普通字符串(官方称呼react元素),但它具备JavaScript全部功能。我们编写的jsx其实会被bable转译成React.createElement()
调用(vue也有类似的createElement
方法),比如下面这段代码是等效的:
const ele = <h1 className="echo">Hello, world!</h1>;
// 等同于
const ele = React.createElement(
"h1", //标签名
{ className: "echo" }, //标签属性
"Hello, world!" //子节点内容
);
而React.createElement()
本质上是创建了一个类似于如下的React对象
,react会读取并编译这些对象,用它们构建页面dom并实时保持更新:
const ele = {
type: 'h1',
props: {
className: 'echo',
children: 'Hello, world!'
}
};
当然这里我们先不用了解的太深,只用知道jsx大致做了什么,以及为什么react中能这么写就足够了,它们的转换过程其实是react元素经过bable转译--->React.createElement()
调用--->react对象--->真实dom。而接下来的语法介绍我想大家会十分熟悉。
react元素支持赋予给变量,比如文章开头的例子也可以写成这样:
const ele = <h1>Hello, world!</h1>;
ReactDOM.render(ele, document.getElementById("root"));
当然,react元素支持嵌套,但需要注意的是,如果我们的结构需要换行,官方推荐使用圆括号包裹你的结构,比如:
const ele = (
<div>
<h1>Hello World!</h1>
<h1>My name's echo!</h1>
</div>
);
ReactDOM.render(ele, document.getElementById("root"));
这样做的好处是能避免代码压缩遇到自动插入分号的陷阱。
在vue开发中,我们习惯使用模板语法{{}}
解析变量,表达式,调用方法等等,其实在react中你同样能这么做,比如:
const myName = "echo";
const add = function (a, b) {
return a + b;
};
const ele = (
<div>
<h1>my name is {myName}</h1>
<h1>{add(2, 2)}</h1>
<h1>{2 + 2}</h1>
</div>
);
ReactDOM.render(ele, document.getElementById("root"));
html标签有属性,react元素与标签一样,同样也支持标签属性以及自定义,比如下面的例子:
const img = "https://pic.cnblogs.com/avatar/1213309/20200507225901.png";
const ele = (
<div>
<div id="icon">头像</div>
<img src={img} alt="icon" />
</div>
);
ReactDOM.render(ele, document.getElementById("root"));
这里需要注意的是,不要在{}
外添加引号,如果你需要解析变量,请使用{}
,如果它只是一个字符串,那么请添加引号,二者选其一添加,两者不要同时使用。
最后,当添加一个jsx结构时只能有一个react根元素,这点与angularjs的自定义指令模板,vue的组件只能有一个根元素情况类似,比如下面这段代码就是错误示范:
const ele = (
<div>1</div>
<div>2</div>
);
正确的做法是为这两个元素添加一个共有的根元素:
const ele = (
<div>
<div>1</div>
<div>2</div>
</div>
);
但请不要将这些jsx的结构理解成react组件,它们只是一些react元素构成的代码块,组件会有专门的方式去创建,这个后面会具体介绍,当然组件也会利用react元素来构建必要的dom结构。
按照我们以往的框架使用经验,当模板语法解析的某个变量发生改变时,页面会自动更新这个变量。但在react中,元素渲染都是一次性的,渲染成功后修改变量,页面并不会有改变,请看下面这个例子:
let num = 0;
setInterval(function () {
num++;
}, 1000);
setInterval(function () {
//控制台输出num
console.log(num);
}, 1000);
const ele = <div>{num}</div>;
ReactDOM.render(ele, document.getElementById("root"));
打开控制台,你会发现num
在不断自增,而页面结构中解析的num
依旧是0,并没有任何变化,这是因为ReactDOM.render
就是一次性执行,它只会调用了一次,因此没办法及时更新num
,比较直接的办法是可以将render
整个过程也包裹在定时器中,比如:
let num = 0;
setInterval(function () {
num++;
}, 1000);
setInterval(function () {
//利用定时器不断更新react元素,以及让render重复渲染
const ele = <div>{num}</div>;
ReactDOM.render(ele, document.getElementById("root"));
}, 1000);
这样做能达到效果,但直观感受这种做法并不友好,其实在后续文档中,react有提供状态专门用于解决这个问题,当然这都是后话了。
其次,我们虽然用定时器反复执行render
,但神奇的是react在每次更新dom时,对比新旧dom结构,并只更新发生变化的部分,打开浏览器控制台,观察dom变化就非常清楚了。这一点相对我之前使用的angularjs,就非常人性化了...
如果您发现该资源为电子书等存在侵权的资源或对该资源描述不正确等,可点击“私信”按钮向作者进行反馈;如作者无回复可进行平台仲裁,我们会在第一时间进行处理!
添加我为好友,拉您入交流群!
请使用微信扫一扫!