从零开始学习React:了解当前React常用技术,编写第一个React组件

React 与 Vue 可以说是现阶段最热门的前端UI框架了,最近开始学习 React,准备开一个新坑:从零开始学习React,主要是学习时的一些思考与记录,如有谬误,烦请斧正。由于前端技术的快速迭代,我会在适当位置标注版本信息,以免出现货不对板。

1. 了解当前 React 常用技术栈

UI 框架 React

React 不必多说,我们要学的就是这个,官网是这样介绍 React 的:

用于构建用户界面的 JavaScript 库

其主要职责便是作为UI界面框架,用于方便我们操作DOM(虚拟DOM)、渲染视图到用户的浏览器中,他与JavaScript的关系就像:Java 之于 AndroidFarmwork,Dart 之于 Flutter。我们之后所有开发工作都离不开React提供的各种接口,没事可以多去官网看文档。

路由框架 React-router-dom

React-router 是由 remix-run 出品的、适用于 React 的前端路由框架,如果你像我一样是 Android 工程师,对路由这个概念可能比较陌生,简而言之就是根据浏览器的不同地址,渲染不同页面。随着 Compose 的兴起,路由的概念目前也开始逐渐的在 Android 中变得重要起来。另外,因为我们是在 React - Web 这样的环境使用,所以一般需要额外配合 React-route-dom 这个库协同使用。

题外话:Flutter 与 Compose 都借鉴了很多 React 中的思想,如果你对这两者有一些了解,接下来的一些概念性的东西就会觉得很熟悉。

状态管理

这涉及到 React 的重要思想:State,如果你有 Flutter 的经验,这应该很好理解。如果对此毫无概念,请参考下面的文章:

  1. React 哲学
  2. FAQ: state 与 props 的区别是什么?
  3. State & 生命周期

在 React 中,UI的渲染都离不开状态State的变化,不同页面的不同组件之间可能涉及到复杂的状态复用、状态变更,这就必然涉及到状态管理,目前在 React 世界中最流行的状态管理库有 Redux、Mobx 等等。

Redux是一个通用的状态管理框架,他不限定你使用什么UI框架,为了方便在 React 中使用,redux团对推出了 React-redux,方便我们使用。

Mobx,是一个类似的状态管理库,但是比起 Redux ,他的使用更为简单一些,这两者在之后我们都会接触到。

React-query,这是一个专注于网络请求状态管理的库,按照 React-query 的思想,将状态拆分为了,普通的用户 UI 前台状态与来源自网络请求的后台状态,React-query 帮我们处理好了一些列关于网络请求的相关状态管理,例如、loading、error、success、refetch等等,是一个非常好用的库。

rtk-query,与 React-query 功能类似,内部使用 redux 实现,可以看做是 Redux 的全家桶一部分,风格更加偏向于 Hook,我们会在后面用案例对比二者。

题外话:React 并不是像 Android 团队那样具有强控制力,在 Android 中几乎一切都有来自官方的各种库的支持,也都存在真正意义上的“最佳实践”,React 与之相反,React 团队似乎只专注于维护 React 本身,其他的一切都交给社区,而前端又是一个乐忠于造轮子的群体,故而在React上并没有真正意义上的“全家桶”、“最佳实践”。

所以用什么、选哪个这个问题,在React上是一个比较难办的事情,我们一般推荐选择比较稳定的、长期在维护的、社区活跃的库,这些库借用mobx官方的说法就是:“是经过战火洗礼的库”,出现问题我们也更容易找到解决方法。

组件库

就像我们上边说的 React 只提供了核心的 UI 框架功能,不借助外力的情况下,组件也只能使用原生标签。蚂蚁金服出品的 AntD 是目前非常主流的一个 React 组件库,提供了很多可以开箱即用的组件,方便我们构建漂亮的前端页面。

2. 上手实操,编写第一个组件

2.1 在 html 中渲染一个组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 准备容器 -->
<div id="root"></div>

<!-- 引入react核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!-- 引入react-dom库 用于支持react操作Dom-->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!-- 引入babel库 用于转换jsx -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
/* type是babel才能使用jsx */
const mid = "myid";
const mdata = "Hell0 react";

//1.创建虚拟dom
const VDOM = (
<h1 className="title" id={mid.toLowerCase()}>
<span style={{color: 'red',fontSize: '34px'}}>{mdata.toLowerCase()}</span>
</h1>
);

//2.渲染虚拟dom到页面
ReactDOM.render(VDOM, document.getElementById("root"));
</script>
</body>

</html>

2.2 什么是 JSX

JSX 这个概念是由 React 提出的,可以把他简单了理解成:我们可以在 js 里直接使用各种 html 标签、各种React组件。

1
2
3
4
5
const VDOM = (
<h1 className="title" id={mid.toLowerCase()}>
<span style={{color: 'red',fontSize: '34px'}}>{mdata.toLowerCase()}</span>
</h1>
);

上面我们使用的 VDOM,就是一个JSX。

为什么会出现 JSX ?我们为什么需要用 JSX ?

如果你对 vue 有一定的了解,你可能知道,在 vue 中对一 个.vue 文件是有由script、template、style,所有的关于页面渲染的基本都放在 template中,通过双向绑定来实现数据渲染显示。

假想这样一个场景,我们从后台接口获取到了某个班级的学生列表,我们希望筛选出全部的:家住在吉林省的男生。

如果我们使用 vue 的话我们需要在 script 中处理好数据逻辑,然后再将这个数组绑定到 v-for 标签中

显然是相对比较麻烦的,如果我们直接使用 JSX 的写法,就会比较清晰明了:

1
2
3
4
5
6
7
8
9
10
11
12
13
//从数据中筛选,并map成JSX元素
const list = data
.filter(item => item.province==='jilin' && item.gender==='man')
.map(item => <li>{item.name}</li>)

....

return (
<div>学生列表:</div>
<ul>
{list}
</ul>
)

2.3 使用JSX的注意事项

  1. 定义虚拟dom时不要用引号,因为JSX元素不是字符串,多行 JSX 应该使用括号包裹
  2. 在标签里使用js对象或者表达时需要用 {}
  3. 标签中样式的类名不要用class,因为这是 js 关键字,要用 className 替代
  4. 标签内联样式 需要用 style={{key:value,key2:value2}}的方式去写,小驼峰
  5. 一个虚拟dom对象 只能有一个根标签
  6. jsx中的所有标签必须闭合
  7. 小写标签直接转换成对应的html标签,大写字母开头的标签识别为react组件

2.4 编写一个组件

在 React 中,有两种编写组件的风格,分别是:1、类式组件;2、函数式组件。在 React 全面引入 Hook 之后,目前的主流就是全面拥抱函数式组件,除非远古项目,否则我们第一选择就是函数式组件。

我们写一个极简的函数式组件,然后将它渲染到root节点:

1
2
3
4
<script type="text/babel">
const H2 = ({ title }) => <h2>{title}</h2>;
ReactDOM.render(<H2 title="这是一个自定义组件" />, document.getElementById("root"));
</script>

这里我们使用函数对象的声明方式,而不是 function 关键字,使用 ES6 的结构赋值获取到标签中传递的 props。

一个函数式组件的最大特征,就是函数的返回值是 JSX 元素,一般的我们使用大写驼峰的命名方式来命名一个组件。

函数式组件的参数被称为 Props,我们在书写标签时,后面传入的 k-v 键值对,都会作为 props 传入函数式组件。