React

您所在的位置:网站首页 如何在react中注入对象数据 React

React

2023-10-10 18:10| 来源: 网络整理| 查看: 265

这篇快速上手指南会教你如何将TypeScript与React结合起来使用。 在最后,你将学到:

使用TypeScript和React创建工程 使用TSLint进行代码检查 使用Jest和Enzyme进行测试,以及 使用Redux管理状态

我们会使用create-react-app工具快速搭建工程环境。

这里假设你已经在使用Node.js和npm。 并且已经了解了React的基础知识。

安装create-react-app

我们之所以使用create-react-app是因为它能够为React工程设置一些有效的工具和权威的默认参数。 它仅仅是一个用来搭建React工程的命令行工具而已。

npm install -g create-react-app 创建新工程

让我们首先创建一个叫做my-app的新工程:

create-react-app my-app --scripts-version=react-scripts-ts

react-scripts-ts是一系列适配器,它利用标准的create-react-app工程管道并把TypeScript混入进来。

此时的工程结构应如下所示:

my-app/ ├─ .gitignore ├─ node_modules/ ├─ public/ ├─ src/ │ └─ ... ├─ package.json ├─ tsconfig.json └─ tslint.json

注意:

tsconfig.json包含了工程里TypeScript特定的选项。 tslint.json保存了要使用的代码检查器的设置,TSLint。 package.json包含了依赖,还有一些命令的快捷方式,如测试命令,预览命令和发布应用的命令。 public包含了静态资源如HTML页面或图片。除了index.html文件外,其它的文件都可以删除。 src包含了TypeScript和CSS源码。index.tsx是强制使用的入口文件。 运行工程

通过下面的方式即可轻松地运行这个工程。

npm run start

它会执行package.json里面指定的start命令,并且会启动一个服务器,当我们保存文件时还会自动刷新页面。 通常这个服务器的地址是http://localhost:3000,页面应用会被自动地打开。

它会保持监听以方便我们快速地预览改动。

测试工程

测试也仅仅是一行命令的事儿:

npm run test

这个命令会运行Jest,一个非常好用的测试工具,它会运行所有扩展名是.test.ts或.spec.ts的文件。 好比是npm run start命令,当检测到有改动的时候Jest会自动地运行。 如果喜欢的话,你还可以同时运行npm run start和npm run test,这样你就可以在预览的同时进行测试。

生成生产环境的构建版本

在使用npm run start运行工程的时候,我们并没有生成一个优化过的版本。 通常我们想给用户一个运行的尽可能快并在体积上尽可能小的代码。 像压缩这样的优化方法可以做到这一点,但是总是要耗费更多的时间。 我们把这样的构建版本称做“生产环境”版本(与开发版本相对)。

要执行生产环境的构建,可以运行如下命令:

npm run build

这会相应地创建优化过的JS和CSS文件,./build/static/js和./build/static/css。

大多数情况下你不需要生成生产环境的构建版本, 但它可以帮助你衡量应用最终版本的体积大小。

创建一个组件

下面我们将要创建一个Hello组件。 这个组件接收任意一个我们想对之打招呼的名字(我们把它叫做name),并且有一个可选数量的感叹号做为结尾(通过enthusiasmLevel)。

若我们这样写,这个组件大至会渲染成Hello Daniel!!!。 如果没指定enthusiasmLevel,组件将默认显示一个感叹号。 若enthusiasmLevel为0或负值将抛出一个错误。

下面来写一下Hello.tsx:

// src/components/Hello.tsx import * as React from 'react'; export interface Props { name: string; enthusiasmLevel?: number; } function Hello({ name, enthusiasmLevel = 1 }: Props) { if (enthusiasmLevel { const hello = enzyme.shallow(); expect(hello.find(".greeting").text()).toEqual('Hello Daniel!') }); it('renders the correct text with an explicit enthusiasm level of 5', () => { const hello = enzyme.shallow(); expect(hello.find(".greeting").text()).toEqual('Hello Daniel!!!!!'); }); it('throws when the enthusiasm level is 0', () => { expect(() => { enzyme.shallow(); }).toThrow(); }); it('throws when the enthusiasm level is negative', () => { expect(() => { enzyme.shallow(); }).toThrow(); });

这些测试都十分基础,但你可以从中得到启发。

添加state管理

到此为止,如果你使用React的目的是只获取一次数据并显示,那么你已经完成了。 但是如果你想开发一个可以交互的应用,那么你需要添加state管理。

state管理概述

React本身就是一个适合于创建可组合型视图的库。 但是,React并没有任何在应用间同步数据的功能。 就React组件而言,数据是通过每个元素上指定的props向子元素传递。

因为React本身并没有提供内置的state管理功能,React社区选择了Redux和MobX库。

Redux依靠一个统一且不可变的数据存储来同步数据,并且更新那里的数据时会触发应用的更新渲染。 state的更新是以一种不可变的方式进行,它会发布一条明确的action消息,这个消息必须被reducer函数处理。 由于使用了这样明确的方式,很容易弄清楚一个action是如何影响程序的state。

MobX借助于函数式响应型模式,state被包装在了可观察对象里,并通过props传递。 通过将state标记为可观察的,即可在所有观察者之间保持state的同步性。 另一个好处是,这个库已经使用TypeScript实现了。

这两者各有优缺点。 但Redux使用得更广泛,因此在这篇教程里,我们主要看如何使用Redux; 但是也鼓励大家两者都去了解一下。

后面的小节学习曲线比较陡。 因此强烈建议大家先去熟悉一下Redux。

设置actions

只有当应用里的state会改变的时候,我们才需要去添加Redux。 我们需要一个action的来源,它将触发改变。 它可以是一个定时器或者UI上的一个按钮。

为此,我们将增加两个按钮来控制Hello组件的感叹级别。

安装Redux

安装redux和react-redux以及它们的类型文件做为依赖。

npm install -S redux react-redux @types/react-redux

这里我们不需要安装@types/redux,因为Redux已经自带了声明文件(.d.ts文件)。

定义应用的状态

我们需要定义Redux保存的state的结构。 创建src/types/index.tsx文件,它保存了类型的定义,我们在整个程序里都可能用到。

// src/types/index.tsx export interface StoreState { languageName: string; enthusiasmLevel: number; }

这里我们想让languageName表示应用使用的编程语言(例如,TypeScript或者JavaScript),enthusiasmLevel是可变的。 在写我们的第一个容器的时候,就会明白为什么要令state与props稍有不同。

添加actions

下面我们创建这个应用将要响应的消息类型,src/constants/index.tsx。

// src/constants/index.tsx export const INCREMENT_ENTHUSIASM = 'INCREMENT_ENTHUSIASM'; export type INCREMENT_ENTHUSIASM = typeof INCREMENT_ENTHUSIASM; export const DECREMENT_ENTHUSIASM = 'DECREMENT_ENTHUSIASM'; export type DECREMENT_ENTHUSIASM = typeof DECREMENT_ENTHUSIASM;

这里的const/type模式允许我们以容易访问和重构的方式使用TypeScript的字符串字面量类型。

接下来,我们创建一些actions以及创建这些actions的函数,src/actions/index.tsx。

import * as constants from '../constants' export interface IncrementEnthusiasm { type: constants.INCREMENT_ENTHUSIASM; } export interface DecrementEnthusiasm { type: constants.DECREMENT_ENTHUSIASM; } export type EnthusiasmAction = IncrementEnthusiasm | DecrementEnthusiasm; export function incrementEnthusiasm(): IncrementEnthusiasm { return { type: constants.INCREMENT_ENTHUSIASM } } export function decrementEnthusiasm(): DecrementEnthusiasm { return { type: constants.DECREMENT_ENTHUSIASM } }

我们创建了两个类型,它们负责增加操作和减少操作的行为。 我们还定义了一个类型(EnthusiasmAction),它描述了哪些action是可以增加或减少的。 最后,我们定义了两个函数用来创建实际的actions。

这里有一些清晰的模版,你可以参考类似redux-actions的库。

添加reducer

现在我们可以开始写第一个reducer了! Reducers是函数,它们负责生成应用state的拷贝使之产生变化,但它并没有副作用。 它们是一种纯函数。

我们的reducer将放在src/reducers/index.tsx文件里。 它的功能是保证增加操作会让感叹级别加1,减少操作则要将感叹级别减1,但是这个级别永远不能小于1。

// src/reducers/index.tsx import { EnthusiasmAction } from '../actions'; import { StoreState } from '../types/index'; import { INCREMENT_ENTHUSIASM, DECREMENT_ENTHUSIASM } from '../constants/index'; export function enthusiasm(state: StoreState, action: EnthusiasmAction): StoreState { switch (action.type) { case INCREMENT_ENTHUSIASM: return { ...state, enthusiasmLevel: state.enthusiasmLevel + 1 }; case DECREMENT_ENTHUSIASM: return { ...state, enthusiasmLevel: Math.max(1, state.enthusiasmLevel - 1) }; } return state; }

注意我们使用了对象展开(...state),当替换enthusiasmLevel时,它可以对状态进行浅拷贝。 将enthusiasmLevel属性放在末尾是十分关键的,否则它将被旧的状态覆盖。

你可能想要对reducer写一些测试。 因为reducers是纯函数,它们可以传入任意的数据。 针对每个输入,可以测试reducers生成的新的状态。 可以考虑使用Jest的toEqual方法。

创建容器

在使用Redux时,我们常常要创建组件和容器。 组件是数据无关的,且工作在表现层。 容器通常包裹组件及其使用的数据,用以显示和修改状态。 你可以在这里阅读更多关于这个概念的细节:Dan Abramov写的表现层的容器组件。

现在我们修改src/components/Hello.tsx,让它可以修改状态。 我们将添加两个可选的回调属性到Props,它们分别是onIncrement和onDecrement:

export interface Props { name: string; enthusiasmLevel?: number; onIncrement?: () => void; onDecrement?: () => void; }

然后将这两个回调绑定到两个新按钮上,将按钮添加到我们的组件里。

function Hello({ name, enthusiasmLevel = 1, onIncrement, onDecrement }: Props) { if (enthusiasmLevel dispatch(actions.incrementEnthusiasm()), onDecrement: () => dispatch(actions.decrementEnthusiasm()), } }

最后,我们可以调用connect了。 connect首先会接收mapStateToProps和mapDispatchToProps,然后返回另一个函数,我们用它来包裹我们的组件。 最终的容器是通过下面的代码定义的:

export default connect(mapStateToProps, mapDispatchToProps)(Hello);

现在,我们的文件应该是下面这个样子:

// src/containers/Hello.tsx import Hello from '../components/Hello'; import * as actions from '../actions/'; import { StoreState } from '../types/index'; import { connect, Dispatch } from 'react-redux'; export function mapStateToProps({ enthusiasmLevel, languageName }: StoreState) { return { enthusiasmLevel, name: languageName, } } export function mapDispatchToProps(dispatch: Dispatch) { return { onIncrement: () => dispatch(actions.incrementEnthusiasm()), onDecrement: () => dispatch(actions.decrementEnthusiasm()), } } export default connect(mapStateToProps, mapDispatchToProps)(Hello); 创建store

让我们回到src/index.tsx。 要把所有的东西合到一起,我们需要创建一个带初始状态的store,并用我们所有的reducers来设置它。

import { createStore } from 'redux'; import { enthusiasm } from './reducers/index'; import { StoreState } from './types/index'; const store = createStore(enthusiasm, { enthusiasmLevel: 1, languageName: 'TypeScript', });

store可能正如你想的那样,它是我们应用全局状态的核心store。

接下来,我们将要用./src/containers/Hello来包裹./src/components/Hello,然后使用react-redux的Provider将props与容器连通起来。 我们将导入它们:

import Hello from './containers/Hello'; import { Provider } from 'react-redux';

将store以Provider的属性形式传入:

ReactDOM.render( , document.getElementById('root') as HTMLElement );

注意,Hello不再需要props了,因为我们使用了connect函数为包裹起来的Hello组件的props适配了应用的状态。

退出

如果你发现create-react-app使一些自定义设置变得困难,那么你就可以选择不使用它,使用你需要配置。 比如,你要添加一个Webpack插件,你就可以利用create-react-app提供的“eject”功能。

运行:

npm run eject

这样就可以了!

你要注意,在运行eject前最好保存你的代码。 你不能撤销eject命令,因此退出操作是永久性的除非你从一个运行eject前的提交来恢复工程。

下一步

create-react-app带有很多很棒的功能。 它们的大多数都在我们工程生成的README.md里面有记录,所以可以简单阅读一下。

如果你想学习更多关于Redux的知识,你可以前往官方站点查看文档。 同样的,MobX官方站点。

如果你想要在某个时间点eject,你需要了解再多关于Webpack的知识。 你可以查看React & Webpack教程。

有时候你需要路由功能。 已经有一些解决方案了,但是对于Redux工程来讲react-router是最流行的,并经常与react-router-redux联合使用。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3