CRA 构建 React 与 TypeScript 开发环境
Create-React-App(CRA) 是 Facebook 推出的脚手架工具用于构建 React 开发环境,快捷简单零配置推荐使用这个脚手架来构建 React 应用(至于我搭的 Yorha Boilerplate 只是代码文件不像 CRA 这样可选择构建生成)。如果 CSS 预处理器选择 stylus 但不知道如何加到 CRA 里可以看我在 Github 发的 CRA 个人用搭建步骤。
TypeScript(TS) 是 JavaScript(JS) 的超集,在 JS 原有的基础上添加了扩展语法并容易掌握,JS 最令人诟病的弱类型语言特性在 TS 中得到了解决,代码完全 OOP 开发,这也可能是后端工程师直接选择学习 TS 而不是 JS 的原因,不必多去了解原型链且 OOP 封装继承多态概念在 TS 中存在。仍需注意的是目前还有许多第三方 JS 类库不支持 TS。如果感兴趣想开始入门学习 TS 可直接看官网文档。
有这样一个问题:JS 是解释型语言还是编译型语言?《你不知道的JS》上卷中第一章就有了很好的解释(这里只是简单的描述,更详细内容还是推荐去看书)。事实上 JS 是一门编译语言,但相比编译过程有三个步骤(分词/语法分析 → 解析/语法分析 → 代码生成)的语言的编译器,JS 要复杂很多,实际上 JS 代码执行前,就已经被「JS 浏览器引擎」或者是「特定的编译环境」例如 NodeJS 编译过。
首先,JS 引擎不会有大量的(像其他语言编译器那么多的)时间用来进行优化,因为与其他语言不同,JS 的编译过程不是发生在构建之前的。对于 JS 来说,大部分情况下编译发生在代码执行前的几微秒(甚至更短!)的时间内。
在 JS 作用域背后,JS 引擎用尽了各种办法(比如 JIT,可以延迟编译甚至实施重编译)来保证性能最佳。简单地说,任何 JS 代码片段在执行前都要进行编译(通常就在执行前)。
简单了解 JS 编译过程后再看看 TS,当运行一段 TS 时,代码首先是 TypeScirpt 编辑器进行的编译阶段,然后才是 JS 引擎的编译阶段,确保代码运行之前是按照预期方式所写的,得益于 TS 编译器代码更易于调试和发现错误。所以会有这样一个段子:一名工程师写了上千行 TS 代码运行后一个报错信息都没有兴奋的打电话给女朋友讲述这件事,女朋友冷漠的回了个字:哦。
CRA 环境搭建
这里开始正题内容,我的 CRA 是安装在全局,希望您和我一样。
npm install -g create-react-app
安装成功后,执行下面命令,初始化项目并带上 scripts-version 参数为 react-scripts-ts。
create-react-app ts-app --scripts-version=react-scripts-ts
react-scripts-ts 参数告诉 CRA 使用 TypeScript 并添加相对应 tools。成功后会生成以下的文件结构:
ts-app/
├─ .gitignore
├─ node_modules/
├─ public/
├─ src/
| — — index.tsx
| — — registerServiceWorker.ts
| — — logo.svg
| — — App.tsx
| — — App.test.tsx
| — — App.css
| — — index.css
| — — assets/
├─ package.json
├─ tsconfig.json
├─ tsconfig.test.json
└─ tslint.json
以下是目录解释:
tsconfig.json
TS 配置声明文件,一般在根目录tslint.json
TSLint 配置文件public
静态资源文件夹用于保存 HTML 与 manifest 文件src
APP 代码目录,包括 TS 组件与 CSS 样式,入口文件 index.js 已被 index.tsx 替换
除了在 TS 中加入配置声明,引入 React 库也需要相对应的声明文件(declaration files)。声明文件可以看做是 TS 与 JS 之间的一个接口。这些声明文件使用@types
前缀。在 ts-app 项目的 package.json 可以看到安装了以下四个声明文件依赖:
@types/jest
@types/node
@types/react
@types/react-dom
在开始用 React 配合 TS 写代码时,需要注意两点,第一是将 .jsx 文件后缀改为 .tsx,关于更多 JSX 介绍可以查阅官网文档 JSX。第二是代码开头引入 React 库时的语法:
import * as React from 'react'; import * as ReactDOM from 'react-dom';
无状态功能组件
在写 props 和 state 代码时一旦理解 interface 的使用(初学还是建议多看文档),那么会比默认的写法好很多。在 React 每个组件里都会定义一个 props interface,这个声明就像对象和类型相关的属性值。这里我创建了一个新的函数组件为 Header,接受一个 name 属性。name? 中的 ? 代表 name 属性的类型为 string 或者 undefined。React.SFC 表示的是无状态功能组件,这个不是必须要写但可以允许使用 defaultProps。
import * as React from 'react'; interface Props { name?: string; } const Header: React.SFC<Props> = (props: Props) => ( <h1> Hello, {props.name}! Welcome to React and TypeScript. </h1> ); Header.defaultProps = { name: 'world', }; export default Header;
然后在 App.tsx 中引入并替换 h1 标签为 Header 组件,就完成了第一个无状态功能组件。
Class 组件
为了展示 Class 组件是如何写,这里就将 App.tsx 中的 p 标签内容替换为我新创建的组件 Description.tsx。Class 组件与函数组件区别第一在于 Class 组件可以创建维护自己的 state,第二在于创建生命周期方法。写 React 的都知道在这里不多提。这个组件有个可选的 prop 为 countBy,下面是 Description.tsx 组件代码:
import * as React from 'react'; interface Props { countBy?: number; } interface State { count: number; } class Description extends React.Component<Props, State> { public static defaultProps: Partial<Props> = { countBy: 1, }; state: State = { count: 0, }; increase = () => { const countBy: number = this.props.countBy!; const count = this.state.count + countBy; this.setState({ count }); } render() { return ( <div> <p> My favorite number is {this.state.count} </p> <button onClick={this.increase}> Increase </button> </div> ); } } export default Description;
具体代码实现逻辑很简单点击按钮后增加 count 值这里不多描述,只是为了展示组件写法,运行命令npm run start
后启动本地预览。
React Types Cheatsheet
// `React.StatelessComponent<P> or React.SFC<P>` const MyComponent: React.SFC<MyComponentProps> = ... // `React.Component<P, S>` class MyComponent extends React.Component<MyComponentProps, State> { ... }; // React.ReactElement<P> or JSX.Element const elementOnly: React.ReactElement = <div /> || <MyComponent />; // React.ReactNode const elementOrPrimitive: React.ReactNode = 'string' || 0 || false || null || undefined || <div /> || <MyComponent />; const Component = ({ children: React.ReactNode }) => { ... }; // React.CSSProperties const styles: React.CSSProperties = { flexDirection: 'row', color: 'red' }; const element = <div style={styles}></div> // React.ReactEventHandler<E> const handleChange: React.ReactEventHandler<HTMLInputElement> = (ev) => { ... }; const element = <input onChange={handleChange} />
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论