手把手教你用 React Hooks 开发移动端网站,从入门到实践
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 感兴趣的同学,欢迎来边敲代码边学习~