Javascript 如何正确地在React中调用GET,返回一个可观察的(类似于Angular中的方法,不使用承诺)?
在Angular中,我通常订阅一个客户机,该客户机为我提供一个GET调用的可观察性Javascript 如何正确地在React中调用GET,返回一个可观察的(类似于Angular中的方法,不使用承诺)?,javascript,reactjs,typescript,rxjs,observable,Javascript,Reactjs,Typescript,Rxjs,Observable,在Angular中,我通常订阅一个客户机,该客户机为我提供一个GET调用的可观察性 httpClient.get(“http://blah") .订阅( 结果=>{…}, 错误=>{…}, () => { ... } ); 我正在尝试学习如何反应并执行相应的操作。我发现的信息是关于使用承诺的,我不喜欢这样。当然,Angular的服务在React中缺少对应的服务,但由于rxjs是一个独立的库,我觉得尝试将其合并到React项目中是有意义的 我如何做到这一点?我在谷歌搜索中遗漏了什么 我还谦虚地考
httpClient.get(“http://blah")
.订阅(
结果=>{…},
错误=>{…},
() => { ... }
);
我正在尝试学习如何反应并执行相应的操作。我发现的信息是关于使用承诺的,我不喜欢这样。当然,Angular的服务在React中缺少对应的服务,但由于rxjs是一个独立的库,我觉得尝试将其合并到React项目中是有意义的
我如何做到这一点?我在谷歌搜索中遗漏了什么
我还谦虚地考虑了另一种选择,因为React基于不同的范例(即存储而不是服务),我可能会陷入一个非常尴尬的境地。只是代替Angular的
httpClient
,您可以使用内置RxJS ajax方法:
import { ajax } from 'rxjs/ajax';
ajax.get('https://httpbin.org/get')
.subscribe(console.log);
现场演示:Angular
Http
之所以能从可观测数据中获益,是因为Angular的某些部分使用了可观测数据,因此可以有效地组合它们,例如,反应形式的可观测数据可以被限制并通过管道传输到Http
。Http
observable被转换为toPromise()
,这并不少见,因为它是完全可观察的,只有一个值,并且可以从async.中获益。当它是一个承诺时,等待
除非React项目大量使用可观测数据(例如,使用redux observable
),否则其收益将远远低于Angular项目
另一个答案提到,RxJS中内置了HTTP请求API,RxJS/ajax
。它是一个围绕XMLHttpRequest
的包装器,这意味着它提供了可取消的请求,而不是一些基于承诺的api,尤其是Fetch。它非常简单,缺少Http
alternative-interceptors等所期望的特性
Axios通常被推荐为与框架无关的、功能齐全的基于承诺的替代品,而不是AngularHttp
。它是按照AngularJS$http
建模的。it部门的承诺可以转化为可观察的承诺,但应采取额外措施使请求可取消
TL;DR:HttpHttp
最大的卖点是它的可观测值可以与其他可观测值组合。如果没有,好处就不那么明显了。承诺可以从async..wait
语法糖中受益,而可观察对象必须以任何方式转换为承诺才能从中受益。如果要取消组件销毁请求并取消输入更改的ajax,请看下一个示例。
使用React挂钩和RxJS提供解决方案:
import React, { useEffect, useState } from "react";
import { ajax } from "rxjs/ajax";
import { debounceTime, delay, takeUntil } from "rxjs/operators";
import { Subject } from "rxjs/internal/Subject";
const App = () => {
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(true);
const [filterChangedSubject] = useState(() => {
// Arrow function is used to init Singleton Subject. (in a scope of a current component)
return new Subject<string>();
});
useEffect(() => {
// Effect that will be initialized once on a react component init.
const subscription = filterChangedSubject
.pipe(debounceTime(200))
.subscribe((filter) => {
if (!filter) {
setLoading(false);
setItems([]);
return;
}
ajax(`https://swapi.dev/api/people?search=${filter}`)
.pipe(
// current running ajax is canceled on filter change.
takeUntil(filterChangedSubject)
)
.subscribe(
(results) => {
// Set items will cause render:
setItems(results.response.results);
},
() => {
setLoading(false);
},
() => {
setLoading(false);
}
);
});
return () => {
// On Component destroy. notify takeUntil to unsubscribe from current running ajax request
filterChangedSubject.next("");
// unsubscribe filter change listener
subscription.unsubscribe();
};
}, []);
const onFilterChange = (e) => {
// Notify subject about the filter change
filterChangedSubject.next(e.target.value);
};
return (
<div>
Cards
{loading && <div>Loading...</div>}
<input onChange={onFilterChange}></input>
{items && items.map((item, index) => <div key={index}>{item.name}</div>)}
</div>
);
};
export default App;
import React,{useffect,useState}来自“React”;
从“rxjs/ajax”导入{ajax};
从“rxjs/operators”导入{debounceTime,delay,takeUntil};
从“rxjs/internal/Subject”导入{Subject};
常量应用=()=>{
const[items,setItems]=useState([]);
const[loading,setLoading]=useState(true);
常量[filterChangedSubject]=useState(()=>{
//Arrow函数用于初始化单例主题。(在当前组件的范围内)
返回新主题();
});
useffect(()=>{
//将在react组件init上初始化一次的效果。
const subscription=filterChangedSubject
.管道(去BounceTime(200))
.订阅((筛选器)=>{
如果(!过滤器){
设置加载(假);
集合项目([]);
返回;
}
阿贾克斯(`https://swapi.dev/api/people?search=${filter}`)
.烟斗(
//当前运行的ajax在过滤器更改时被取消。
takeUntil(过滤器更改主题)
)
.订阅(
(结果)=>{
//设置项目将导致渲染:
设置项(结果、响应、结果);
},
() => {
设置加载(假);
},
() => {
设置加载(假);
}
);
});
return()=>{
//在组件销毁时。通知takeUntil取消订阅当前正在运行的ajax请求
filterChangedSubject.next(“”);
//取消订阅筛选器更改侦听器
订阅。取消订阅();
};
}, []);
常量onFilterChange=(e)=>{
//将过滤器更改通知主题
filterChangedSubject.next(如target.value);
};
返回(
卡
{正在加载和正在加载…}
{items&&items.map((item,index)=>{item.name})
);
};
导出默认应用程序;
您是否有不使用承诺的特定动机?在很多情况下,在Angular中使用Http observable并没有真正的好处(基本上是管道、取消和重试)。我发现自己在90%的情况下使用toPromise(),因为它可以很好地处理async..wait
。在React中,好处要少得多,除非你已经在整个应用程序中大量使用了可观测数据。@estus我将在一段较长的时间内发射数据,并在数据可用时拍摄值。关于RxJS如何与React一起使用,没有太多信息的原因是React没有可作为源使用的可观测数据。因此,您正在做的事情不是特定于框架的。顺便说一句,您也可以将承诺与mergeMap
一起使用。从Angular中提取Http
,并在React中使用它也不是一个坏主意。
import React, { useEffect, useState } from "react";
import { ajax } from "rxjs/ajax";
import { debounceTime, delay, takeUntil } from "rxjs/operators";
import { Subject } from "rxjs/internal/Subject";
const App = () => {
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(true);
const [filterChangedSubject] = useState(() => {
// Arrow function is used to init Singleton Subject. (in a scope of a current component)
return new Subject<string>();
});
useEffect(() => {
// Effect that will be initialized once on a react component init.
const subscription = filterChangedSubject
.pipe(debounceTime(200))
.subscribe((filter) => {
if (!filter) {
setLoading(false);
setItems([]);
return;
}
ajax(`https://swapi.dev/api/people?search=${filter}`)
.pipe(
// current running ajax is canceled on filter change.
takeUntil(filterChangedSubject)
)
.subscribe(
(results) => {
// Set items will cause render:
setItems(results.response.results);
},
() => {
setLoading(false);
},
() => {
setLoading(false);
}
);
});
return () => {
// On Component destroy. notify takeUntil to unsubscribe from current running ajax request
filterChangedSubject.next("");
// unsubscribe filter change listener
subscription.unsubscribe();
};
}, []);
const onFilterChange = (e) => {
// Notify subject about the filter change
filterChangedSubject.next(e.target.value);
};
return (
<div>
Cards
{loading && <div>Loading...</div>}
<input onChange={onFilterChange}></input>
{items && items.map((item, index) => <div key={index}>{item.name}</div>)}
</div>
);
};
export default App;