大家好,我是奶綠茶。
今天來分享 rxjs + axios 的即時 Search。
當使用者輸入一個文字時,打 api
當使用者輸入第二個文字時,剛剛呼叫的 api 要 cancel
避免使用者打字太快,加個 debounceTime 優化一下
我們要先把 axios 包裝成 rxjs 物件
在建立時,同使產生 CancelToken
這裡要注意一下,使 cancel 發生時,會觸發 Promise reject
不過可以透過 axios.isCancel 來判斷
class AxiosSubscriber extends Subscriber {
constructor(observer, url:string) {
super(observer);
this.completed = false;
this.cancelSource = CancelToken.source();
axios.get(url, {
cancelToken: this.cancelSource.token,
})
.then((response) => {
this.completed = true;
observer.next(response.data);
observer.complete();
})
.catch((error) => {
this.completed = true;
if (axios.isCancel(error)) { // axios cancel 會觸發 catch 事件
observer.complete();
} else {
observer.error(new Error(error.response.data.error));
}
});
}unsubscribe() {
super.unsubscribe();
// cancel XHR
console.log('unsubscribe this.completed:', this.completed);
if (this.completed === false) {
this.cancelSource.cancel('axios cancel');
this.completed = true;
}
this.cancelSource = null;
delete this.cancelSource;
}
}
再來就是 rxjs 的部份
function searchAjaxObservable(dom:HTMLInputElement, url:string) {
return fromEvent(dom, 'input')
.pipe(
pluck('target', 'value'),
debounceTime(200),
distinctUntilChanged(),
switchMap((value) => {
const urlWithQ = `${url}?q=${value}`;
return fromAxios(urlWithQ)
.pipe(
catchError((err) => {
console.log('Handling error ', err);
return of({ error: err.message });
}),
);
}),
);
}
fromEvent: 偵聽 事件
pluck: 取 event.target.value 值
debounceTime
distinctUntilChanged 如果輸入的文字和上一個文字不一樣
switchMap 把本來的 rxjs stream 轉換另一個新的 stream
接著接上我們自定的 fromAxios 函式
程式進入點:
const input:HTMLInputElement = document.getElementById('input');
const resultDOM:HTMLDivElement = document.getElementById('result');searchAjaxObservable(input, '/api/data')
.subscribe((result) => {
resultDOM.innerHTML = JSON.stringify(result);
});
打完收工,rxjs 真心推
參考文章:
https://github.com/zhaosiyang/axios-observable/blob/master/lib/create-observable.ts