React 已经是 JavaScript 生态系统中最受欢迎的前端框架之一。尽管人们已经对它赞不绝口,但 React 团队仍然在努力让它变得更好。
在 2018 ReactConf 大会上,React 官方发布了 Hooks,随后它席卷了整个 React 开发界。
React Hooks 是 React 库的新增功能,它允许你编写状态逻辑并使用其他 React 功能,同时无需编写类组件。你甚至可以单独使用 Hooks 来制作自己的应用程序,这对 React 相关的从业者来说是一次重大变革。
今天给大家带来一门 React Hooks 的课程React Hooks 从入门到实践 ,课程将对 React Hooks 做全方位的分析,并通过纯 Hooks 函数组件对 CNode 网站进行移动端页面的开发,实战过程中还会介绍前端开发中常用技术栈的使用。
课程实战用到的技术栈 React + React-Router+ Antd-Mobile + Axios ,实战部分使用最新 vw 方式做移动端的适配,抛弃 rem 的形式拥抱变化。重写 Axios 请求库,做到请求返回统一处理。开发环境的搭建可以作为一个种子项目,方便在工作中启动新项目时直接使用。
项目效果图:
教程开始:
React 作为 Facebook 推出的前端主流框架之一,在版本升级上一直是采用平滑升级的模式。在升新版本的时候,无论是增加或者删除了某些 API,React 都能做到版本向后兼容,也就是用旧版本的写法,最新的 React 包也能做到基本支持。这次也不例外,在 v16.8 版本引入了全新的 API,名叫 React Hooks。引用官方的解释就是三个点
- 完全可选的。你无需重写任何已有代码就可以在一些组件中尝试 Hooks。但是如果你不想,你不必现在就去学习或使用 Hooks。
- 100% 向后兼容的。Hooks 不包含任何破坏性改动。
- 现在可用。Hooks 已发布于 v16.8.0。
React 官方没有计划从 React 中移除 Class,但是我相信不久的将来,Hooks 将被大范围使用。相比之下 Hooks 可以涵盖所有 Class 组件的应用场景,且提供了更高的灵活性、可测试性和代码的复用能力。Hooks 不会影响你对 React 概念的理解。恰恰相反,Hooks 为已知的 React 概念提供了更直接的 API:props, state,context,refs 以及生命周期。在后面的章节里,笔者还会一一介绍上面列出的 API。
Dan Abramov 在社交他的社交网站上也毫不吝啬的给出了他的想法。
Hooks 将会是 React 的未来。
我们为什么不再需要 Class 组件
存在即是合理的,React Hooks 要解决的问题是状态共享,是继 render-props 和 higher-order components 之后的第三种状态共享方案,不会产生 JSX 嵌套地狱问题。这个状态指的是状态逻辑,所以称为 状态逻辑复用会更恰当,因为只共享数据处理逻辑,不会共享数据本身。
在 React Hooks 推出之前,React 便已经有函数组件了,那么已经有了函数组件,为什么开始还要引入 Class 组件呢?
早些时候的 React 组件以有无状态(state)分为两种,代码如下。
// 有状态组件
class Hello extends React.Component {
constructor(props) {
super(props)
this.state = {
text: 'Hello World'
}
render() {
return <div>{text}</div>
}
}
}
// 无状态组件
// 状态通过父组件传入
const Hello = (props) => <div>{props.text}</div>
我们可以通过 Class 组件的 this 上下文去保存和访问状态(state),但是函数组件在其作用域内很难维持住这个状态,试想如果再次运行函数的话,所有的状态都将被重置。所以我们才一直使用 Class 的形式编写有状态组件。
Hooks 编写函数组件,它的状态是如何维持的呢
了解过 React Fiber 的同学应该知道,类组件中的状态其实保存在 Fiber 的属性 memoizedState 上,并不是在 Class 的 this.state 上。那么回过头来看 React Hooks 组件的状态,其实也是去访问 Fiber 上的 memoizedState 属性,这样看来,问题就迎刃而解了。
两种写法的对比分析
繁重的写法。
下面是一段简单的以 Class 形式书写的组件代码。
import React, { Component } from "react";
export default class MyButton extends Component {
constructor() {
super();
this.state = {
text: "点击"
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({
text: "改变"
});
}
render() {
const { text } = this.state;
return <button onClick={this.handleClick}>{text}</button>;
}
}
仅仅是需要一个按钮组件,代码量已经接近 20 行之多,可能你会觉得 20 行并不多,但是当组件内部需要控制一些状态的时候,那代码量就不仅仅是 20 行这么简单了。包括整个 React 项目都是由各个组件拼装而成,层层嵌套,再加上状态管理插件如 Redux、Mobx 等,就会是一场 “灾难”。
反观 Hooks 的写法:
import React from "react";
export default const MyButton = () => {
const [text, setText] = useState('点击')
return <button onClick={setText('改变')}>{text}</button>
}
在 Hooks 出现之前,React 也是可以用函数写组件的,但是只能写一些无状态的纯组件 (Pure Component) ,也就是内部是不能有属于自己的状态变量。上述代码中 Hooks 实现了函数组件管理自身状态的方式,不仅在代码量上得以控制,书写上也简便了不少。受限于现代浏览器,所有最新 ES6 + 的写法,不是所有浏览器都会支持。类组件的写法在经过 babel 编译后会编译成 ES5 写法,才能让各大浏览器得以支持和运行。这就导致了编译后类组件比函数组件多一层继承 React.Component 的代码,从这个角度出发,Hooks 写法降低了编译后的代码了减少 bundle 包的大小。
复杂组件变得难以理解。
随着组件代码的增多,状态与状态紧密相连,想把组件拆分的细致那就变得难上加难。重复的逻辑在不同的组件和生命周期函数之间不断出现,到那时项目就变得不可维护。
开发环境的搭建
课程总共为 10 章,1 ~ 8 章以实例和原理讲解为主,9 ~ 10 章 为实战章节。
所以 1 ~ 8 章笔者只需要通过官方提供的项目初始化工具 create-react-app 来完成课程内部代码的讲解。
首先电脑里必须事先安装 Node 环境。
检测当前 Node 版本和 NPM 版本,执行命令行。
node -v
npm -v
如果已经安装过的同学会打印出相应的 Node 版本,当然实验楼也提供了前端的开发环境,内置 Node 和 NPM,已经在全局安装了 cnpm 包,同学尽量使用 cnpm 安装 node_modules 包,因为有些包是放在国外的服务器,直接使用 npm 可能会安装不上或者需要很久的时间,对大家的开发体验也是不好的。
全局安装 create-react-app。
cnpm install create-react-app -g
安装完毕之后,通过指令可以生成项目。
// my-app 为项目文件夹的名字,可自定义
npx create-react-app my-app
or
npm init react-app myapp
初始化项目结束之后,进入进入文件夹,通过 npm run start 启动项目,默认的端口会是 3000,而实验楼在线开发环境只对外开放 8080 端口,所以我们要对文件里的脚本做一些改动。
有两种方式改变 create-react-app 初始化项目的开发环境启动端口。
- 修改 package.json 的 scripts 属性。
"scripts": {
"start": "PORT=8080 react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
要注意的是,如果是 Windows 用户建议在 PORT 前加上一个 cross-env,需要通过 cnpm install cross-env -D 下载到开发依赖 devDependencies 中。
cross-env 是一个运行跨平台设置和使用环境变量的脚本 .cross-env 使得您可以使用单个命令,而不必担心为平台正确设置或使用环境变量。
- 通过修改 node_modules/react-scripts/scripts/start.js 脚本第 60 行的端口号,如下。
// line 60
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 8080;
端口修改完之后,点开右边的 “Web 服务”,会在浏览器打开一个在线页面,如下图所示。
打开浏览器,你会遇到如下报错。
原因是实验楼环境启动的在线网址是 https 协议,而项目热更新用的是 ws 协议,所以我们需要将 ws 协议改成 wss 协议。打开项目 node_modules 目录,找到 node_modules/react-dev-utils/webpackHotDevClient.js 脚本,将第 60 行修改为 wss 如下图。
重新通过 npm run start 启动项目,再次点开 “Web 服务”,如下图所示,便是实验环境配置成功。
项目运行的时候有强迫症的同学可以关闭 eslint ,具体方法首先运行指令:
npm run eject
根目录会多出一个 config 文件夹,进入文件夹打开脚本 webpack.config.js,把 eslint 的配置关闭,如下图所示
将红框的内容注释之后,重启项目,命令行就会不显示 eslint 语法报错。
篇幅有限,今天就介绍到这里,对 前端 和 React Hooks 感兴趣的同学,欢迎来实验楼边敲代码边学习~