作者:一只图雀
仓库: Github 、 Gitee
图雀社区主站(首发): 图雀社区
博客: 掘金 、 知乎 、 慕课
公众号: 图雀社区
联系我:关注公众号后可以加图雀酱微信哦
原创不易,:heart:点赞+评论+收藏 :heart:三连,鼓励作者写出更好的教程
因为需要尽可能全且精炼的讲解 TypeScript 语法知识,所以我们需要一个恰到好处的实战项目,这一小节主要是用于讲解我们准备初始 TypeScript 版本的 React 项目代码的过程,在下一个小节中我们将会结合 React 项目代码,真正开始 TypeScript 语法的讲解。
本文所涉及的源代码都放在了 Github 或者 Gitee 上,如果您觉得我们写得还不错,希望您能给 :heart:这篇文章点赞 Github 或 Gitee 仓库加星❤ ️哦~
此教程属于 React 前端工程师学习路线 的一部分,欢迎来 Star 一波,鼓励我们继续创作出更好的教程,持续更新中~
初始一个 React 应用的最佳方式那么一定是 React 官方维护的 Create React App 脚手架了,我们打开终端,运行如下命令来初始化一个 TypeScript 版本的 React 应用:
$ npx create-react-app typescript-tea --template typescript
运行如上命令,命令行里面应该会有一系列输出,等待几分钟,就会提示已经初始化完成,并提供了对于的命令来帮助你开启项目,我们根据提示输入如下命令来开启项目:
$ cd typescript-tea $ npm start
运行如上命令之后,会自动开启 Webpack 开发服务器,并打开浏览器窗户,访问 http://localhost:3000/ 来展示你的应用初始界面:
如果看到这个界面,恭喜你 !成功创建一个 TypeScript 版本的 React 应用!
提示
在下文中,为了简化语言,我们统一称 TypeScript 为 TS。
实战驱动的技术学习能带给我们成就感,便捷好用的包可以加快我们的开发效率,好看的界面可以提高我们的审美能力,缓解学习疲劳。在这篇教程的讲解过程中,我们将通过 Ant Design 对应的 React 组件库 antd 来辅助我们项目的编写,使得我们可以专注于讲解 TS 的核心知识,而不被繁杂的界面语言所干扰,还能做出对应相应完成的目标功能。
提示
Ant Design 是蚂蚁金服孵化的一套企业级产品设计体系,提供了完备的 TS 类型定义,使得我们可以很方便的在 TS 项目中使用,在最近发布了 4.0 版本,致力于创造高效愉悦的工作体验。
除此之外 Ant Design 的周边生态也很丰富:
后面图雀社区计划围绕 Ant Design 生态撰写一系列教程,帮助大家提高设计、开发效率,敬请期待!:v:
好了,大致介绍了 antd 组件库及 Ant Design 周边之后,我们马上来写代码引入 antd,打开命令行,在其中输入如下命令:
$ npm install antd
运行上面的命令安装完依赖之后就可以在项目中使用了,但是为了更好的定制样式和按需引用以减小打包之后的包体积,我们还需要做一点定制化的操作,打开命令行,依次安装如下依赖:
$ npm install react-app-rewired customize-cra babel-plugin-import less less-loader
注意到上面我们安装了很多包,我们来依次解释一下上面各种包的意思:
最后我们安装一个在 Ant Design 4.0 拆分出去的 icons 包,可以用来按需引用 icons,进一步减少最后的打包体积,继续在命令行运行如下命令:
$ npm install @ant-design/icons
大功告成!现在我们所有的依赖以及安装完成。接下来就需要改写一下 CRA 之前通过 react-scripts
跑开发构建的流程,用我们安装的 react-app-rewired
脚本来替换它,当安装完了所以依赖,以及用 react-app-rewired
替换 react-scripts
之后,我们的 package.json
文件应该是下面的样子:
// ... "version": "0.1.0", "private": true, "dependencies": { "@ant-design/icons": "^4.0.2", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^7.1.2", "@types/jest": "^24.0.0", "@types/node": "^12.0.0", "@types/react": "^16.9.0", "@types/react-dom": "^16.9.0", "antd": "^4.0.0", "babel-plugin-import": "^1.13.0", "customize-cra": "^0.9.1", "less": "^3.11.1", "less-loader": "^5.0.0", "react": "^16.13.0", "react-app-rewired": "^2.1.5", "react-dom": "^16.13.0", "react-scripts": "3.4.0", "typescript": "~3.7.2" }, "scripts": { "start": "react-app-rewired start", "build": "react-app-rewired build", "test": "react-app-rewired test", "eject": "react-scripts eject" }, // ...
安装完依赖之后,我们要确保对应改写 CRA 流程的配置生效,我们需要根据 react-app-rewired
的文档说明在根目录下建立 config-overrides.js
文件,并在其中编写如下的内容:
const { override, fixBabelImports, addLessLoader } = require("customize-cra"); const darkThemeVars = require("antd/dist/dark-theme"); module.exports = override( fixBabelImports("import", { libraryName: "antd", libraryDirectory: "es", style: true }), addLessLoader({ javascriptEnabled: true, modifyVars: { hack: `true;@import "${require.resolve( "antd/lib/style/color/colorPalette.less" )}";`, ...darkThemeVars, "@primary-color": "#02b875" } }) );
可以看到,上面的代码主要是导出一个用于修改 Webpack 配置的对象,使用 override
API,接收两个修改配置的函数调用, fixBabelImports
用于配置 antd 的按需引用, addLessLoader
用于配置 antd 的主题,这里我们使用了 Ant Design 4.0 新带来的 Dark Mode(暗色模式),然后配置了主题色为图雀社区的主题色: #02b875
,代表希望的绿色。:laughing:
自此,我们就引入了 antd 组件库,并进行了按需配置使用以及配置主题色和使用了 Ant Design 最新的暗色主题 -- Dark Mode。
接下来,我们将使用 antd 帮助我们快速的编写一下我们即将实现的待办事项的界面,打开 src/App.tsx
,对其中的代码做出对应的修改如下:
import React, { useState, useRef } from "react"; import { List, Avatar, Button, Typography, Form, Input, Select, DatePicker, Menu, Dropdown, Tabs } from "antd"; import { DownOutlined } from "@ant-design/icons"; import "./App.css"; import logo from "./logo.svg"; const { Title } = Typography; const { Option } = Select; const { TabPane } = Tabs; const todoListData = [ { content: "图雀社区:汇聚精彩的免费实战教程", user: "mRcfps", time: "2020年3月2日 19:34", isCompleted: false }, { content: "图雀社区:汇聚精彩的免费实战教程", user: "pftom", time: "2020年3月2日 19:34", isCompleted: false }, { content: "图雀社区:汇聚精彩的免费实战教程", user: "Holy", time: "2020年3月2日 19:34", isCompleted: false }, { content: "图雀社区:汇聚精彩的免费实战教程", user: "crxk", time: "2020年3月2日 19:34", isCompleted: false }, { content: "图雀社区:汇聚精彩的免费实战教程", user: "Pony", time: "2020年3月2日 19:34", isCompleted: false } ]; const userList = [ { id: "666666666", name: "图雀社区", avatar: "https://avatars0.githubusercontent.com/u/39240800?s=60&v=4" }, { id: "23410977", name: "mRcfps", avatar: "https://avatars0.githubusercontent.com/u/23410977?s=96&v=4" }, { id: "25455350", name: "crxk", avatar: "https://avatars1.githubusercontent.com/u/25455350?s=96&v=4" }, { id: "23410977", name: "pftom", avatar: "https://avatars0.githubusercontent.com/u/23410977?s=96&v=4" }, { id: "58352313", name: "holy", avatar: "https://avatars0.githubusercontent.com/u/58352313?s=96&v=4" } ]; const menu = ( <Menu> <Menu.Item>完成</Menu.Item> <Menu.Item>删除</Menu.Item> </Menu> ); const TodoInput = ({ value = {} }) => { return ( <div className="todoInput"> <Input type="text" placeholder="输入待办事项内容" /> <Select style={{ width: 80 }} size="small" defaultValue="666666666"> {userList.map(user => ( <Option value={user.id}>{user.name}</Option> ))} </Select> <DatePicker size="small" style={{ marginLeft: "16px", marginRight: "16px" }} /> </div> ); }; function TodoList() { return ( <List className="demo-loadmore-list" itemLayout="horizontal" dataSource={todoListData} renderItem={item => ( <List.Item actions={[ <Dropdown overlay={menu}> <a key="list-loadmore-more"> 操作 <DownOutlined /> </a> </Dropdown> ]} > <List.Item.Meta avatar={ <Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" /> } title={<a href="https://ant.design">{item.user}</a>} description={item.time} /> <div>{item.content}</div> </List.Item> )} /> ); } function App() { const callback = () => {}; const onFinish = () => {}; const ref = useRef(null); return ( <div className="App" ref={ref}> <div className="container header"> <img src={logo} alt="" /> <Title level={3}>图雀社区:汇聚精彩的免费实战教程</Title> </div> <div className="container"> <Form onFinish={onFinish}> <Form.Item name="todo"> <TodoInput /> </Form.Item> </Form> </div> <div className="container"> <Tabs onChange={callback} type="card"> <TabPane tab="所有" key="1"> <TodoList /> </TabPane> <TabPane tab="进行中" key="2"> <TodoList /> </TabPane> <TabPane tab="已完成" key="3"> <TodoList /> </TabPane> </Tabs> </div> </div> ); } // ...
上面的代码主要就是一系列初始数据的准备,antd 组件的使用,编写起来的大致轮廓,还没有涉及到任何的 TS 语法,但这个是我们开始项目的基础,读者只需要进行简单的复制放进现有的 typescript-tea
项目中对应的 src/App.tsx
中即可。
准备了逻辑代码之后,为了让我们最后的待办事项在样式上更美观一点,也利于我们讲解时的操作,我们需要给项目加一点样式,打开 src/App.css
对其中的代码做出对应的修改如下:
.App { display: flex; flex-direction: column; align-items: center; padding-top: 60px; } .container { width: 600px; } .header { text-align: center; margin-bottom: 56px; } .header img { width: 160px; height: 160px; margin-bottom: 24px; } .todoInput { display: flex; flex-direction: row; align-items: center; height: 40px; border: 1px solid #434343; } .todoInput input { border: none; }
这个时候如果你的服务器还在运行,那么你应该可以看到如下效果:
好了!所有的准备工作已经就绪,在开始下一节真正的 TS 学习之前,我们先来回顾一下我们在这个小节中所完成的工作:
react-app-rewired
替换默认的 react-scripts
来完成对 CRA 的 Webpack 配置进行修改,以是我们可以获得 antd 组件的按需引用和主题定制的功能 我们在前面铺垫了大量的 TypeScript 的优点以及花了不少笔墨来准备初始代码,想必读到这里的读者们可能已经等不及要马上见识一下 TS 的庐山真面目了吧!马上就来啦!
本文所涉及的源代码都放在了 Github 或者 Gitee 上,如果您觉得我们写得还不错,希望您能给 :heart:这篇文章点赞 Github 或 Gitee 仓库加星❤ ️哦~