从零开始的react入门教程(一),让我们从hello world开始
壹 ❀ 引
按照之前的计划,从这个月开始,我将由浅至深更新一些react相关的技术博文。由于我目前也是react新手一名,所以文章本质上也算自己学习历程的记录,倘若这些文章能帮助到一些人那就再好不过了。那么这一篇文章就作为一个新的开端,从零开始一起变得更强吧,本文开始。
贰 ❀ 准备工作
在学习基础知识之前,我们可以在本地搭建并运行一个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!,恭喜你,到这里我们成功创建了第一个属于自己的应用,虽然它目前还很简单,但通过后面的学习,我们来一起让它变得更酷!
叁 ❀ jsx基础
按照以往传统的开发习惯,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,就非常人性化了...
伍 ❀ 总
那么到这里,我们成功在本地搭建了一个属于自己的应用,并了解了react中jsx语法,以及一些常见的用法。学习完这些内容,我们可以利用react元素构建出一些简单的静态页面,虽然现在还未涉及组件概念,当然这些将会在后续文章中展开。
不知不觉又凌晨一点了,这篇文章就先写到这里,那么本文结束。