- 创建一个React和TypeScript项目
- 创建一个类组件
- 处理类组件的事件
- 类组件的状态
- 类组件声明周期方法
- 创建一个函数组件
¶创建一个React和TypeScript项目
¶使用create-react-app
create-eract-app
是一个npm包的命令行工具,用于快速创建React和TypeScript应用。
1 | npx create-react-app my-react-ts-app --typescript |
项目创建后,添加TSLint,
1 | cd my-react-ts-app |
添加文件tslint.json
,包含一些规则,
1 | { |
启动,
1 | npm start |
¶创建一个简单的React component
1 | import * as React from "react"; |
React.SFC
是一个TypeScript的React类型,它不包含任何内部状态。
1 | import * as React from "react"; |
¶添加webpack
(略)
¶项目目录结构
(略)
¶创建一个基本的类组件
1 | import * as React from "react"; |
render
方法决定了该组件需要展示的内容。我们用JSX来定义需要展示的内容。简单来说,JSX就是HTML和JavaScript的混合。
1 | public render() { |
怎么使用Confirm
组件?在App.tsx
中,
1 | import Confirm from './Confirm'; |
¶JSX
JSX看起来很像HTML,它不是有效的JavaScript,我们需要一个处理步骤将其转换为JavaScript。
打开浏览器,进入https://babeljs.io/repl,输入下面内容,
1 | <span>This is where our title should go</span> |
右侧会获得编译之后的JS文件,
1 | React.createElement( |
React.createElement
有三个参数,
- 元素类型,可以是一个HTML标签,一个React组件类型,或一个React 代码段
- 属性对象
- 子类或内容
例如,
1 | <div className="confirm-title-container"> |
最终会被编译为,
1 | React.createElement( |
现在看是有意义的,但目前仅由HTML构筑。加点JavaScript代码看看,
1 | const props = { |
它会被编译为,
1 | var props = { |
更进一步,让字面量props
为空,
1 | const props = {}; |
内嵌调用原封不变,
1 | React.createElement( |
因此,为什么我们使用
className
属性而不是class
?现在知道JSX会编译为JavaScript,由于class
是JavaScript的关键字,在JSX包含class
属性会发生冲突。因此React使用className
代替CSS引用。
¶Component props
目前,组件Confirm
的标题和内容是硬编码的。需要将这些引用属性以组件形式接收
- 首先,我们需要为我们的props定义个TypeScript类型。我们将会用到一个接口,
1 | interface IProps { |
- 将该
IProps
类型以尖括号引入定义中,
1 | class Confirm extends React.Component<IProps> |
React.Component
被称为泛型类。泛型类允许类型允许在内部传递使用。在我们的例子中,我们传递了IProps
接口。
- 然后我们的类内使用
this.props.propName
。在我们的JSX文件中,可以直接引用这些属性,取代硬编码的方式:
1 | ... |
目前编译不过,因为Confirm
组件现在要求传入title
和content
属性,
修改为,
1 | <Confirm |
¶Optional props
接口Props的内容可以定义为可选属性,
1 | interface IProps { |
¶Default prop values
当组件被初始化,可以被组件添加默认props属性值。它通过一个称为
defaultProps
的静态对象字面量实现。
- 创建默认的
cancelCaption
和okCaption
,
1 | class Confirm extends React.Component<IProps> { |
如果要覆盖默认属性,补充具体属性值即可,
1 | <Confirm |
带有默认值的可选属性便于组件使用,这样大部分通用的配置可以自动装配起来,不用逐个指定。
¶处理类组件事件
事件存在于多数编程语言中。以允许我们执行特定逻辑。
¶基础事件句柄
所有的本地JavaScript事件都可以在JSX中处理。JSX允许我们通过属性来调用这些事件函数。本地事件名会被带上前缀
on
以峰驼方式传递。因此,例如在JS中的属性事件是click
,在JSX则对应onClick
。
要查看所有可用事件列表,可以前往node_modules/@types/react
文件夹的index.d.ts
文件
- 首先是我们需要处理按钮上的
click
事件,对应上为,
1 | <button className="confirm-ok" onClick={this.handleOkClick}>...</button> |
- 创建这个
handleOkClick
方法,
1 | private handleOkClick() { |
¶The this problem
在事件的处理上承受来自JavaScript的经典this
问题。我们在事件处理上获取不到引用,譬如,
1 | private handleOkClick() { |
点击按钮,会出现undefined!!原因是this
代表的是当前这个事件,而不是我们的类!
一种解决方法是,将handleOkClick
方法改为箭头函数(arrow function)。
arrow function相当于一个表达式。它不会创建自身的
this
——这样解决了this
的问题。
我们把原来的方法改一改,
1 | private handleOkClick = () => { |
现在再次点击按钮,程序正常了。
¶Function props
有时候需要在组件消费者(component)中传递事件处理逻辑。
- 修改对应的IProps接口,对应函数类型属性,
1 | interface IProps { |
然后在消费方引用函数属性,
1 | <Confirm |
¶类组件状态
状态是一个对象,它决定了组件的行为和渲染。我们需要在我们的app中引入状态,以管理我们Confirm窗口打开或关闭。
State的定义和Props类型,首先我们需要创建一个接口,
1 | interface IState { |
接着传递React.Component
的第二个泛型参数中,
1 | class App extends React.Component<{}, IState> |
¶Initializing the state
定义的状态需要被初始化,初始化动作在构造函数中实现,
1 | constructor(props: {}) { |
state被存放在组件类内的一个私有属性中。以及可以在组件内被使用。
1 | <Confirm |
¶Changing state
状态的改变不能直接访问控制,
1 | private handleOkConfirmClick = () => { |
它会出现错误消息说状态是read-only!的。我们需要使用setState
方法来改变状态。
1 | private handleOkConfirmClick = () => { |
我们仅能在构造函数中初始化State,其它类组件任何地方都不能初始化状态。以及,状态的更改,仅能在该组件内调用setState
实现。
¶Class component life cycle methods
生命周期允许我们在特定点做某些处理。
¶componentDidMount
当一个组件被插入到DOM中时,componentDidMount
被调用。下面是一些该方法常见的用例:
- 调用web service以获取某些数据
- 添加事件监听
- 初始化计时
- 初始化第三方库
1 | private timer: number = 0; |
¶componentWillUnmount
当组件从DOM内被移除时触发componentWillUnmount
,下面是常见的用例,
- 移除事件监听器
- 取消激活的网络请求
- 移除计时器
1 | public componentWillUnmount() { |
¶getDerivedStateFromProps
每次组件被渲染时,触发getDerivedStateFromProps
。它是一个组件的静态方法,返回改变的状态或返回null。
1 | public static getDerivedStateFromProps(props: {}, state: IState) { |
¶getSnapshotBeforeUpdate and componentDidUpdate
¶shouldComponentUpdate
¶Creating a function component
函数组件是从JavaScript函数实现的。
¶Creating a basic function component
1 | const Confirm: React.SFC<IProps> = (props) => { |
完整示例如下,
1 | import * as React from "react"; |
¶Stateful function components
富状态函数组件,
1 | const Confirm: React.SFC<IProps> = props => { |