作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
在丰富而强大的网络和移动应用程序不断增长的生态系统中, 有越来越多的状态需要管理, 喜欢当前用户, 加载的项目列表, 加载状态, 错误, 还有更多. 回来的是解决这个问题的一种方法,它将状态保存在一个全局对象中.
回来的的一个限制是它不支持 异步行为 开箱即用. 对此的一个解决方案是 redux-可观测The
它基于RxJS, RxJS是JavaScript中用于响应式编程的强大库. RxJS是反应iveX的一个实现, 一种用于响应式编程的API,起源于微软. 反应iveX结合了响应式范式的一些最强大的特性, 函数式编程,观察者模式和迭代器模式.
在本教程中,我们将学习回来的及其与反应的使用. 我们还将探讨 反应性编程 使用RxJS,以及它如何使繁琐和复杂的异步工作变得非常简单.
最后, 我们将学习redux-可观测The, 一个利用RxJS进行异步工作的库, 然后使用回来的和回来的 -可观测的在反应本地中构建一个应用程序.
正如它在GitHub上描述的那样,回来的是“JavaScript应用程序的可预测状态容器”.“它为JavaScript应用程序提供了一个全局状态, 保持状态和动作远离反应组件.
在没有回来的的典型反应应用程序中, 我们必须通过属性将数据from根节点传递给子节点, or 道具
. 这种数据流对于小型应用程序来说是可管理的,但随着应用程序的增长,它会变得非常复杂. 回来的允许我们拥有彼此独立的组件, 因此,我们可以把它作为真理的单一来源.
回来的可以在反应中使用 react-redux
, 它为反应组件提供绑定,以便from回来的读取数据并调度操作以更新回来的状态.
回来的可以被描述为三个简单的原则:
的 状态 整个应用程序的所有数据都存储在一个对象中. 在回来的中,这个对象由 商店. 在任何回来的应用程序中都应该有一个单独的商店.
»控制台.日志(存储.getState ())
«{用户:{...}, todos: {...} }
要from反应组件中的回来的中读取数据,我们使用 连接
函数 react-redux
. 连接
接受四个参数,它们都是可选的. 现在,我们将关注第一个,叫做 mapStateToProps
.
/ * UserTile.js */
from'react-redux'导入{连接};
类UserTile扩展反应.组件{
呈现(){
return { 这.道具.用户.name }
}
}
mapStateToProps(状态) {
返回{用户: 状态.用户}
}
导出默认连接(mapStateToProps)(UserTile)
在上面的例子中, mapStateToProps
接收全局回来的状态作为其第一个参数,并返回一个对象,该对象将与传递给的道具Merge
它的父组件.
回来的状态对于反应组件来说是只读的,改变状态的唯一方法是发出一个 行动. 动作是表示改变状态意图的普通对象. 每个动作对象都必须有 类型
字段,且值必须为字符串. 除此之外,操作的内容完全取决于你,但大多数应用程序都遵循 flux-st和ard-行动 为mat,它将一个动作的结构限制为只有四个键:
类型
操作的任何字符串标识符. 每个动作都必须有一个独特的动作.有效载荷
任何操作的可选数据. 它可以是任何时间,并包含有关动作的信息.错误
任何可选的布尔属性,如果操作表示错误,则设置为真正的. 这类似于被拒绝 承诺. 字符串
操作的标识符. 每个动作都必须有一个独特的动作. 按照惯例,当 错误
is 真正的
, 有效载荷
应该是错误对象吗.meta
元可以是任何类型的值. 它适用于不属于有效负载的任何额外信息.下面是两个行动的例子:
商店.调度({
类型:“可以”,
有效载荷:“21”,
});
商店.调度({
类型:“GET_USER_SUCCESS”,
有效载荷:{
用户:{
id: '21',
名称:“Foo”
}
}
});
全局回来的状态是使用称为reducers的纯函数更改的. 减速器接受前一个状态和动作并返回下一个状态. reducer创建一个新的状态对象,而不是改变现有的状态对象. 根据应用的大小,回来的 商店可以有一个或多个reducer.
/ *存储.js */
from“redux”中导入{combineReducers, createStore}
函数用户(状态 = {}, 行动) {
开关(行动.类型){
例“GET_USER_SUCCESS”:
返回操作.有效载荷.用户
默认值:
返回状态
}
}
函数todos(状态 = [], 行动) {
开关(行动.类型){
例“ADD_TODO_SUCCESS”:
返回(
...状态,
{
Id: uuid(), //随机uuid生成器函数
文字:行动.文本,
完成:假
}
]
例“COMPLETE_TODO_SUCCESS”:
返回状态.map(todo => {
如果(待办事项.Id === 行动.id) {
返回{
...待办事项,
完成:真
}
}
返回待办事项
})
默认值:
返回状态
}
}
const rootReducer = combineReducers({用户, todos})
const 商店 = createStore(rootReducer)
与读取状态类似,我们可以使用a 连接
分派动作的函数.
/ * UserProfile.js */
类配置文件扩展反应.组件{
h和leSave(用户){
这.道具.updateUser(用户);
}
}
mapDispatchToProps(调度){
返回({
updateUser: (用户) => 调度({
类型:“GET_USER_SUCCESS”,
用户,
}),
})
}
导出默认连接(mapStateToProps, mapDispatchToProps)(Profile);
响应式编程是一种声明式编程范式,它处理数据流。流以及它的传播和变化. RxJS是一个用于JavaScript响应式编程的库,它有一个概念 可见,这是一个观察者可以看到的数据流 订阅 ,该观察者将随时间传递数据.
一个可观察对象的观察者是一个具有三个函数的对象: 下一个
, 错误
, 完整的
. 所有这些函数都是可选的.
可观测的.订阅({
下一个: value => console.log(' Value是${Value} '),
错误: err => console.日志(err),
完整的: () => console.日志('完成'),
})
的 .订阅
函数也可以有三个函数而不是一个对象.
可观测的.订阅(
value => console.log(' Value是${Value} '),
err => console.日志(err),
() => console.日志(完成)
)
我们可以通过创建an的对象来创建一个新的可观察对象 可观测的
,传入一个接收订阅者(即观察者)的函数. 订阅者有三个方法: 下一个
, 错误
, 完整的
. 订阅者可以根据需要多次使用值调用下一个,并且 完整的
or 错误
最后. 后调用 完整的
or 错误
,可观察对象不会将任何值推入流中.
fromrxjs中导入{Observable}
const 可观察到的美元 = new 可观测的 (function 订阅(订阅者)) {
const intervalId = setInterval(() => {
订阅者.下一个(“嗨”);
订阅者.完成()
clearInterval (intervalId);
}, 1000);
});
可观察到的美元.订阅(
value => console.log(' Value是${Value} '),
err => console.日志(err)
)
上面的示例将打印 价值是高的
1000毫秒后.
每次手工创建一个可观察对象会变得冗长乏味. 因此,RxJS有很多函数来创建一个可观察对象. 一些最常用的是 of
, from
, ajax
.
of
接受一个值序列并将其转换为流:
fromrxjs中导入{of}
of(1,2,3, 'Hello', 'World').订阅(value => console.日志(值))
// 1 2 3 Hello World
from
将几乎所有内容转换为值流:
fromrxjs中导入{from}
From ([1,2,3]).订阅(控制台.日志)
// 1 2 3
(新承诺.解决(“Hello World”)).订阅(控制台.日志)
// 'Hello World'
from(fibonacciGenerator).订阅(控制台.日志)
// 1 1 2 3 5 8 13 21 ...
ajax
接受字符串URL或创建一个可观察对象来发出HTTP请求. ajax
有一个功能 ajax.getJSON
, 它只返回嵌套的响应对象fromAJAX调用没有返回的任何其他属性 ajax ()
:
from'rxjs/ajax'中导入{ajax}
ajax (http://jsonplaceholder.typicode.com/todos/1”).订阅(控制台.日志)
//{请求,响应:{用户Id, id, title, 完整的d}, responseType, status}
ajax.getJSON(“http://jsonplaceholder.typicode.com/todos/1”).订阅(控制台.日志)
// {用户Id, id, title, 完整的d}
Ajax ({url, 方法, headers, body}).订阅(控制台.日志)
// {...}
有很多方法可以创建一个可观察对象(你可以看到完整的列表) 在这里).
操作符是RxJS的一个真正的发电站, 它有一个操作员,几乎任何你需要的东西. fromRxJS 6开始, 操作符不是可观察对象上的方法,而是应用在可观察对象上的纯函数 .管
方法.
map
接受一个单参数函数,并对流中的每个元素应用投影:
fromrxjs中导入{of}
from“rxjs/operators”中导入{map}
of(1, 2, 3, 4, 5).管(
map(i=> i * 2)
).订阅(控制台.日志)
// 2, 4, 6, 8, 10
Filter
接受单个参数,并from流中删除给定函数返回false的值:
fromrxjs中导入{of}
from“rxjs/operators”中导入{map, Filter}
of(1, 2, 3, 4, 5).管(
map(i => i * i),
Filter(i => i % 2 === 0)
).订阅(控制台.日志)
// 4, 16
flatMap
Operator接受一个函数,该函数将蒸汽中的每个项映射到另一个流中,并将这些流的所有值扁平化:
fromrxjs中导入{of}
from'rxjs/ajax'中导入{ajax}
fromrxjs/operators中导入{flatMap}
of(1, 2, 3).管(
flatMap(page => ajax.toJSON (http://example.com/blog?大小= 2&页面页面= ${}”)),
).订阅(控制台.日志)
//[{博客1},{博客2},{博客3},{博客4},{博客5},{博客6}]
Merge
按照到达的顺序Merge两个流中的项:
from'rxjs'中导入{interval, Merge}
fromrxjs/operators中导入{管, take, mapTo}
Merge(
时间间隔(150).管(带(5),mapTo (' A ')),
时间间隔(250).管(带(5),mapTo (B))
).订阅(控制台.日志)
// a b b a b b a b b b
操作符的完整列表是可用的 在这里.
按照设计,回来的中的所有操作都是同步的. 回来的-可观测的是回来的的中间件,它使用可观察流来执行异步工作,然后在回来的中调度另一个带有异步工作结果的操作.
回来的-可观测的是基于 史诗. 史诗是一个执行一系列动作的函数, 以及可选的状态流,并返回动作流.
函数(行动$: Observable<行动>, 状态$: StateObservable<状态>):可观察到的<行动>;行动>状态>行动>
按照惯例,每个流变量(_aka _可观测的
)以a结尾 $
. 在我们使用redux-可观测The之前,我们必须把它作为中间件添加到我们的商店中. 因为史诗是由可观察对象组成的流,而每一个动作的退出都会被重新输送到流中, 返回相同的操作将导致无限循环.
const epic = 行动$ => 行动$.管(
Filter(行动 => 行动.类型 === 'FOO'),
mapTo({类型: 'BAR'}) //不改变返回的操作类型
//也会导致无限循环
)
// or
from'redux-可观测The'中导入{ofType}
const epic = 行动$ => 行动$.管(
减低(“FOO”),
mapTo({类型: BAZ'})
)
可以把这种响应式体系结构想象成一个管道系统,其中每个管道的输出反馈到每个管道, 包括自己, 还有回来的的还原器. 这些管道顶部的Filter决定了什么可以进入,什么被阻挡.
让我们看看乒乓史诗是如何运作的. 它接收一个ping,将其发送到服务器,并在请求完成后将一个pong发送回应用程序.
const pingEpic = 行动$ => 行动$.管(
减低(“平”),
flatMap(行动 => ajax('http://example.com/pinger ')),
mapTo({类型: 'PONG'})
)
现在,我们将通过添加史诗和检索用户来更新原始的todo存储.
from“redux”中导入{combineReducers, createStore}
from“redux-可观测The”中导入{ofType, combineepic, createEpicMiddleware};
fromrxjs/operators中导入{map, flatMap}
from'rxjs/ajax'中导入{ajax}
// ...
/*如上定义的用户和任务减少器*/
const rootReducer = combineReducers({用户, todos})
createEpicMiddleware();
const 用户Epic = 行动$ => 行动$.管(
减低('可以'),
flatMap(() => ajax.getJSON(“http://foo.酒吧.com/get-用户 ')),
map(用户 => ({ 类型:“GET_USER_SUCCESS”, 有效载荷: 用户}))
)
const addTodoEpic = 行动$ => 行动$.管(
减低(“ADD_TODO”),
flatMap(行动 => ajax({
url: http://foo.酒吧.com/add-todo’,
方法:“文章”,
正文:{text:动作.有效载荷}
})),
map(data => data.反应),
map(todo => ({ 类型: 'ADD_TODO_SUCCESS', 有效载荷: todo }))
)
const 完整的TodoEpic = 行动$ => 行动$.管(
减低(“COMPLETE_TODO”),
flatMap(行动 => ajax({
url: http://foo.酒吧.com/完整的-todo’,
方法:“文章”,
主体:{id: 行动.有效载荷}
})),
map(data => data.反应),
map(todo => ({ 类型: 'COMPLEE_TODO_SUCCESS', 有效载荷: todo }))
)
const rootEpic = combineepic (用户Epic, addTodoEpic, 完整的TodoEpic)
const 商店 = createStore(rootReducer, applyMiddleware(epicMiddleware))
epicMiddleware.运行(rootEpic);
重要:史诗就像RxJS中的任何其他可观察流一样. 它们可能以完整状态或错误状态结束. 在此状态之后,史诗和您的应用程序将停止工作. 所以你必须抓住蒸汽中每一个潜在的错误. 你可以使用 __catchError__
这个操作符. 更多信息: redux-可观测The中的错误处理.
添加一些UI后,一个(最小的)演示应用看起来像这样:
我们了解了什么是响应式应用. 我们还了解到 回来的、RxJS和redux-可观测The,甚至用反应本地在Expo上创建了一个响应式Todo应用. 为 反应 和 反应本地 开发人员,目前的趋势提供了一些非常强大的 状态管理选项.
再一次,这个应用程序的源代码是打开的 GitHub. 欢迎在下面的评论中分享你对响应式应用状态管理的看法.
回来的是JavaScript应用程序的一个可预测的全局状态容器. 它将状态管理和变更传播逻辑from应用程序的反应组件中抽象出来.
响应式编程是一种声明式编程范式,它将数据作为流处理,并通过该流传播状态变化.
反应iveX是一个用于可观察流异步编程的API. 它结合了来自观察者模式的最佳想法, 迭代器模式, 函数式编程.
RxJS是反应iveX API在JavaScript中的实现库. 它利用了JavaScript的动态特性以及广泛的反应iveX API.
微软的计算机科学家Erik Meijer创建了反应iveX API及其实现 .网。. RxJS是作为Rx的一个移植而创建的.网。由不同的工程师.
RxJS为用函数式编程处理异步任务提供了大量API, 这有助于使用重试之类的操作, 节流, 指数回退, 缓存, 错误处理, 和更多的.
回来的 -可观测的是一个在回来的中处理异步任务的库. 它的工作原理是from回来的捕获一个已调度的操作,并对其执行一些异步工作. 工作完成后, redux-可观测The
通过调度另一个操作将响应添加到回来的状态容器中.
RxJS是反应iveX的实现,可以与任何状态管理或UI库一起使用, 或者甚至是普通的JavaScript. 它提供了一个强大的API来管理可观察流形式的异步工作. 这些流可以连接到任何其他库或直接使用. 在JavaScript之外,您可以在反应iveX上找到针对常见语言的反应iveX实现.io.
苏拉布拥有广泛而通用的技能. 他在移动和后端开发方面的经验使他能够快速构建原型.
世界级的文章,每周发一次.
世界级的文章,每周发一次.