前言
最近这段时间忙着公司项目和带娃,发表技术文章就被搁置了半个月之久。为了答谢读者和我的粉丝们,趁着周末完成了一个小Dome项目,前端技术用到 React全家桶 + TypeScript + Antd。恶补了一下相关知识点,就迫不及待的想着分享出来。其实自己很久都没用过的 React.js 前端框架,大厂必备面试必问,作为前端三大主流框架之一,也是最流行的,因为它的设计很优秀。之前作者一直都在用 Vue.js 框架,是最火的一门前端框架,它是中国人开发的,对我们来说,文档要友好一些,上手更快。💪
基于 Vue.js 前端框架开发的开源项目如下:
- NodeJS全栈开发一个功能完善的Express项目(附完整源码)
- Nodejs全栈进阶-Vue+Express+Webpack自建脚手架完善单页应用,档次瞬间提高(附完整源码)
- Vue+Echarts构建大数据可视化酷炫展示公司品牌实战项目分享(附源码)
React 是什么?
介绍
- React 是一个用于构建用户界面的 JAVASCRIPT 库;
- React 主要用于构建UI,很多人认为 React 是 MVC 中的 V(视图);
- React 起源于 Facebook 的内部项目,用来架设 Instagram 的网站,并于2013年 5月开源;
- React 拥有较高的性能,代码逻辑非常简单,越来越多的人已开始关注和使用它。
特点
- 声明式设计 - React 采用声明范式,可以轻松描述应用;
- 高效 - React 通过对 DOM 的模拟,最大限度地减少与 DOM 的交互;
- 灵活 - React 可以与已知的库或框架很好地配合;
- JSX - JSX 是 JavaScript 语法的扩展,React 开发不一定使用 JSX ,但我们建议使用它;
- 组件化 - 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中;
- 单向响应的数据流 − React 实现了单向响应的数据流,从而减少了重复代码,这也是它为什么比传统数据绑定更简单。
缺点
- 对于一直使用 JS,jQuery 的传统前端,React 非常不友好;
- React 强调组件和状态管理,其世界观是面向程序语言的;
- Vue.js 强调视图的自动同步,其世界观是面向UI脚本的;
- React 的学习成本较 Vue.js 高;
- React 本身没有全家桶,只做UI界面。
为什么要用 React ?
- 和其他框架相比,React 设计很优秀,一切基于 JavaScript 并且实现了组件化开发的思想;
- 开发团队实力强悍,不必担心不更新的情况;
- 强大的社区支持,很多问题都能找到对应的解决方案;
- 提高工作效率,虚拟 DOM 操作,组件可复用,有效使用开发工具;
- 受到大厂的信赖,前端项目的技术选型采用的是 React.js;
- 提供了无缝切换到 React Native 上的移动端开发体验,让我们的技术能力得到了拓展,增强了我们的核心竞争力。
React的设计思想及其独特,属于革命性创新,性能出众,代码逻辑却非常简单。所以,越来越多的人开始关注和使用,认为它可能是将来WEB开发的主流工具。😋
理解几个核心概念👍
虚拟 DOM(Virtual Document Object Model)
- DOM 的本质是什么:浏览器中的概念,用JS对象来表示页面上的元素,并提供了操作 DOM 对象的 API;
- 什么是 React 中的虚拟 DOM:是框架中的概念,是程序猿用JS对象来模拟页面上的 DOM 元素和嵌套关系(虚拟 DOM是以JS对象的形式存在);
- 为什么要实现虚拟 DOM:为了实现页面中,DOM 元素的高效更新。
Diff 算法
- Tree Diff - 新旧两棵 DOM 树,逐层对比的过程,就是 Tree Diff。当整棵 DOM 树逐层对比完毕,则所有需要被按需更新的元素,必然能够找到;
- Component Diff - 在进行 Tree Diff 的时候,每一层中,组件级别的对比,叫做 Component Diff。如果对比前后,组件的类型相同,则暂时认为此组件不需要被更新。如果对比前后,组件类型不同,则需要移除旧组件,创建新组件,并追加到页面上;
- Element Diff - 在进行组件对比的时候,如果两个组件类型相同,则需要进行元素级别的对比,这叫做 Element Diff。
生命周期函数
1)组件创建阶段:一辈子只执行一次
-
componentWillMount:组件将要被挂载(16.3版本以后已废弃);
-
render:第一次开始渲染真正的虚拟DOM,当render执行完。内存中就有完整的虚拟DOM了;
-
componentDidMount:组件完成挂载,此时组件已经显示在页面上。
2)组件运行阶段:按需根据props属性或state状态的改变,有选择性的执行0次到多次
-
componentWillReceiveProps:组件将要接受新的属性(16.3版本以后已废弃);
-
shouldComponentUpdate:组件是否需要进行更新。此时,组件尚未被更新;
-
componentWillUpdate:组件将要被更新(16.3版本以后已废弃);
-
render:根据新的state和props重新的渲染内存中的虚拟DOM数;
-
componentDidUpdate:此时页面被重新渲染。
3)组件销毁阶段:一辈子只执行一次
- componentWillUnmount:组件将要被卸载的时候。
高阶组件
高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。
具体而言,高阶组件是参数为组件,返回值为新组件的函数。
组件是将 props 转换为 UI,而高阶组件是将组件转换为另一个组件。
状态state和属性props的区别
- 从来源上来看,状态是组件内部创建并维持的,属性虽然也可以在组件内创建,但一般是从父组件传递过来;
- 属性可以由父组件修改,状态不能;
- 父组件能设置子组件的属性初始值,状态不行;
- 状态只能在组件内部更新,属性除非外部组件主动传来新的props否则永远保持不变。
以上内容是对React的初步认识,如需详细学习可以移步到React官网reactjs.org/
TypeScript 是什么?
介绍
- TypeScript 是 JavaScript 类型的超集,支持 ECMAScript 6 标准;
- TypeScript 由微软开发的自由和开源的编程语言;
- TypeScript 设计目标是开发大型应用,它可以编译成纯 JavaScript,编译出来的 JavaScript 可以运行在任何浏览器、任何计算机和任何操作系统上。
语言特性
- 类型批注和编译时类型检查
- 类型推断
- 类型擦除
- 接口
- 枚举
- Mixin
- 泛型编程
- 名字空间
- 元组
- async / await
- 类
- 模块
- 箭头函数表达式
- 可选参数和默认参数
为什么要用 TypeScript?
- 增加了代码的可读性和可维护性,增加了编辑器和IDE的功能;
- 拥有活跃的社区,拥抱 ES6 规范;
- TypeScript 非常包容,后缀 .js 文件可以直接重命名 .ts 即可。
缺点
- 有一定的学习成本,需要理解接口(Interfaces)、泛型(Generics)、类(Classes)、枚举类型(Enums)等前端工程师可能不是很熟悉的概念;
- 短期可能会增加一些开发成本,毕竟要多写一些类型的定义,不过对于一个需要长期维护的项目,TypeScript 能够减少其维护成本;
- 集成到构建流程需要一些工作量;
- 可能和一些库结合的不是很完美。
上述内容是对 TypeScript 的初步认识,如需详细学习可以移步到TypeScript官网www.typescriptlang.org/
另外推荐学习 TypeScript 入门教程
Ant Design of React (简称 antd)
介绍
antd 是基于 Ant Design 设计体系的 React UI 组件库,主要用于研发企业级中后台产品。
特性
- 🌈 提炼自企业级中后台产品的交互语言和视觉风格。
- 📦 开箱即用的高质量 React 组件。
- 🌀 使用 TypeScript 开发,提供完整的类型定义文件。
- ⚙️ 全链路开发和设计工具体系。
- 🌍 数十个国际化语言支持。
- 🎨 深入每个细节的主题定制能力。
前后端分离
前端项目采用的技术栈是基于React全家桶 + TS + Antd
,用create-react-app
官方脚手架构建的前端界面,后端项目采用的技术栈是基于Node.js + Express + MySQL
,用Express搭建的后端服务器。
在线演示DEMO地址👉:http://106.55.168.13:9000/
如果觉得还不错的话,就请给个👍和❤️收藏,您们的点赞是作者继续创作的动力。
部分效果截图
目录结构
│ .gitignore // git忽略配置
│ config-overrides.js // webpack自定义配置
│ package.json // npm包管理所需模块及配置信息
│ paths.json // src路径配置
│ tsconfig.json // typescript配置
│ yarn.lock // 自动锁定安装包版本
├─public
│ favicon.ico // 图标
│ index.html // 入口html文件
└─src
│ App.tsx // 路由组件
│ declaration.d.ts // 依赖声明文件
│ index.tsx // 入口主文件
│ react-app-env.d.ts // 声明文件
├─assets // 存放公共图片
├─components // 公共组件
│ 404.tsx // 错误页面
│ Footer.tsx // 底部模板组件
│ Header.tsx // 头部模板组件
├─router
│ config.js // 项目路由配置
│ index.js // 单页面路由注册组件
│ permissionAuth.js // 登录权限控制组件
├─store // 全局store状态管理
│ │ actionTypes.js // 拆分actionType的类型定义常量
│ │ index.js // 创建store管理仓库
│ ├─actions // 拆分action,将它封装到一个函数里面去管理
│ │ auth.js // 权限action单独管理
│ │ index.js // 合并多个不同action,统一对外输出
│ │ user.js // 用户action单独管理
│ └─reducers // 创建reducer,更新state数据操作
│ index.js // 合并多个不同reducer,统一对外输出
│ user.js // 创建用户reducer,更新state数据操作
├─styles
│ base.less // 基础样式
│ footer.less // 底部样式
│ header.less // 头部样式
│ home.less // 首页样式
│ login.less // 登录样式
├─utils
│ api.js // 统一封装API接口调用方法
│ network.js // axios封装与拦截器配置
│ url.js // 自动部署服务器环境
│ valid.js // 统一封装公用模块方法
└─views
Home.tsx // 首页
Login.tsx // 登录页面
前端部分
技术栈
- create-react-app
- React v16.13
- react-router-dom v5.2
- redux v4.0
- react-redux v7.2
- react-thunk v2.3
- typescript v3.7
- antd v4.5
- axios v0.19
- react-persist v6.0
功能模块
- 登录(登出)
- 注册
- 记住密码
- 忘记密码(修改密码)
- todoList增删改查
- 点亮红星标记
- 查询条件筛选
- 错误页面
代码实现
在 TypeScript 中使用 create-react-app
官方脚手架一步步地创建一个 TypeScript 项目,并引入 antd。
准备工作
请确保电脑上已经安装 nodejs v10+ 或者最新版的 yarn。
// 使用npm安装yarn
npm i yarn -g
// 查看版本号
yarn -v
推荐全部使用yarn安装依赖包及运行项目,保证畅通无阻,速度飞快。
请将npm设置为淘宝源
npm config set registry https://registry.npm.taobao.org
npm config set disturl https://npm.taobao.org/dist
请将yarn设置为淘宝源
yarn config set registry https://registry.npm.taobao.org --global
yarn config set disturl https://npm.taobao.org/dist --global
安装和初始化
使用yarn或npm创建项目
npx create-react-app react-ts-antd --typescript
OR
yarn create react-app react-ts-antd --template typescript
进入项目并启动
cd react-ts-antd
yarn start
此时浏览器会访问 http://localhost:3000/,看到 Welcome to React 的界面就算成功了。
引入 antd 和 less 文件
- 安装依赖
// less-loader必须指定5.0版本
yarn add antd less less-loader@5.0.0
- 在src/index.tsx文件顶部引入antd样式
import 'antd/dist/antd.less';
- 或者在src/base.less文件顶部引入antd样式
@import '~antd/dist/antd.less';
- 在自定义组件中按需引入antd的相关组件,比如按钮组件
import * as React from 'react';
import { Button } from 'antd';
import 'antd/dist/antd.less';
class Custom extends React.Component {
render() {
return (
<div className="container">
<Button type="primary">按钮</Button>
</div>
)
}
};
export default Custom;
webpack 自定义配置
引入 react-app-rewired 和 customize-cra
yarn add react-app-rewired customize-cra -D
修改package.json文件
将react-scripts命令全部替换成react-app-rewired,已改代码如下:
"scripts": {
"start": "set BROWSER=none&& set PORT=9000&& react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-app-rewired eject"
}
另外开发环境配置关闭浏览器自动打开以及更改默认端口号3000
set BROWSER=none&& set PORT=9000&& react-app-rewired start
配置config-overrides.js文件
在项目根目录下(和package.json同级)新建配置文件 config-overrides.js,并添加如下内容:
const {
override,
fixBabelImports,
addLessLoader,
addWebpackPlugin,
addWebpackAlias,
addDecoratorsLegacy,
overrideDevServer
} = require('customize-cra');
const path = require('path');
const webpack = require('webpack');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const CompressionWebpackPlugin = require('compression-webpack-plugin');
const isProduction = process.env.NODE_ENV === 'production';
function resolve (pathUrl) {
return path.join(__dirname, pathUrl);
}
const addCustomize = () => (config) => {
// 配置打包后的文件位置
// config.output.path = resolve('dist');
if (config.output.publicPath) {
config.output.publicPath = '/';
// isProduction ? '/react-ts-antd-admin/' : '/';
}
if (config.resolve) {
config.resolve.extensions = ['.js', '.tsx', '.less', '.css'];
}
// 添加js、css打包gzip配置
config.plugins.push(
new CompressionWebpackPlugin({
test: /\.js$|\.css$/,
threshold: 1024,
}),
)
return config;
};
// 设置代理
const devServerConfig = () => config => {
return {
...config,
proxy: {
'/api': {
target: 'http://106.55.168.13:9000',
changeOrigin: true,
secure: false
}
}
};
};
// 关掉 sourceMap
process.env.GENERATE_SOURCEMAP = isProduction ? 'false' : 'true';
module.exports = {
webpack: override(
// 判断环境,只有在生产环境的时候才去使用这个插件
isProduction && addWebpackPlugin(new UglifyJsPlugin({
uglifyOptions: {
compress: {
drop_debugger: true,
drop_console: true
}
}
})),
// 配置antd按需引入
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: true, // 自动打包相关的样式
}),
// 使用less-loader对源码中的less的变量进行重新指定
addLessLoader({
javascriptEnabled: true,
modifyVars: { '@primary-color': '#2d8cf0' },
}),
// 配置路径别名
addWebpackAlias({
'@': resolve('src'),
}),
// 支持装饰器
addDecoratorsLegacy(),
// 压缩JS等
addCustomize()
),
// 本地启动配置,可以设置代理
devServer: overrideDevServer(devServerConfig())
};
配置 antd 按需加载组件
yarn add babel-plugin-import -D
const { override, fixBabelImports } = require('customize-cra');
const webpack = require('webpack');
module.exports = {
webpack: override(
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: true,
})
);
}
通过引入 customize-cra 模块中的 addLessLoader 来实现 antd 自定义主题
const { override, addLessLoader } = require('customize-cra');
const webpack = require('webpack');
// 利用less-loader的modifyVars参数来进行主题配置
module.exports = {
webpack: override(
addLessLoader({
javascriptEnabled: true,
modifyVars: {}
})
);
}
配置装饰器
yarn add @babel/plugin-proposal-decorators -D
const { override, addDecoratorsLegacy} = require('customize-cra');
const webpack = require('webpack');
module.exports = {
webpack: override(
addDecoratorsLegacy()
);
}
以上基本工作已准备就绪,架构搭建也已完善,下面终于要进入页面组件功能开发,心情十分鸡冻,敲代码的日子才刚刚开始。一般开发项目之前,需要先分析页面需求,有哪些功能模块(功能扩展),技术选型,有无技术难点(是否可替代),哪些组件可复用,手机适配,前端性能考虑,是否多人协作开发,与后端约定API接口规则等等。时间过得真快,周末就过完了,先写到这吧~🐶
写在最后
由于时间关系,文章写的仓促,难免会有些小问题或BUG出现,愿接受批评和指正。此次实战项目分享内容分为上下两篇文章。下一篇要分享的内容大概是结合实例讲解React全家桶的组合使用、有状态组件和无状态组件的使用、组件间通信、封装工具函数库、前端性能优化、RESTFUL API接口开发等等。
如果小伙伴看完,感觉还不错的话,老铁们是不是来github里赏个★Star鼓励一哈。你们的赞和
star
是作者编写更多更精彩文章的动力!
github地址:github.com/jackchen012…
此项目其实还有很多不足或优化的地方,也期望与大家一起交流学习。😃
推荐阅读相关优质文章
- 开发一款微信小程序的个性简历,能打开大厂之门并获得门票?(附源码)
- Vue+Echarts构建大数据可视化酷炫展示公司品牌实战项目分享(附源码)
- 前端必知必会MySQL的那些事儿 - NodeJS全栈成长之路
- 2020值得收藏与学习280多款H5小游戏,从入门到彻底了解它(附源码)
欢迎关注作者公众号:懒人码农