(上)手摸手教你大厂都在用 React+TS+Antd 快速入门到NodeJS全栈项目实战(附源码)

10,906 阅读13分钟

前言

最近这段时间忙着公司项目和带娃,发表技术文章就被搁置了半个月之久。为了答谢读者和我的粉丝们,趁着周末完成了一个小Dome项目,前端技术用到 React全家桶 + TypeScript + Antd。恶补了一下相关知识点,就迫不及待的想着分享出来。其实自己很久都没用过的 React.js 前端框架,大厂必备面试必问,作为前端三大主流框架之一,也是最流行的,因为它的设计很优秀。之前作者一直都在用 Vue.js 框架,是最火的一门前端框架,它是中国人开发的,对我们来说,文档要友好一些,上手更快。💪

基于 Vue.js 前端框架开发的开源项目如下:

React 是什么?

介绍

  • React 是一个用于构建用户界面的 JAVASCRIPT 库;
  • React 主要用于构建UI,很多人认为 React 是 MVC 中的 V(视图);
  • React 起源于 Facebook 的内部项目,用来架设 Instagram 的网站,并于2013年 5月开源;
  • React 拥有较高的性能,代码逻辑非常简单,越来越多的人已开始关注和使用它。

特点

  1. 声明式设计 - React 采用声明范式,可以轻松描述应用;
  2. 高效 - React 通过对 DOM 的模拟,最大限度地减少与 DOM 的交互;
  3. 灵活 - React 可以与已知的库或框架很好地配合;
  4. JSX - JSX 是 JavaScript 语法的扩展,React 开发不一定使用 JSX ,但我们建议使用它;
  5. 组件化 - 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中;
  6. 单向响应的数据流 − 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…

此项目其实还有很多不足或优化的地方,也期望与大家一起交流学习。😃

推荐阅读相关优质文章

欢迎关注作者公众号:懒人码农