觀察者模式
觀察者模式也叫釋出訂閱模式. 最經典的用法就是在事件監聽裡面.
<button onClick = "handle()">確認</button>
handle方法訂閱了onClick事件,當使用者點選(釋出)onClick, handle方法觸發
複製程式碼
大致提一下,網上對觀察者模式的解釋有很多. Observable就是基於觀察者模式實現的
Observable方法的定義
基本特徵:
- 是一個函式
- 接受一個Observer物件
- 返回一個具有unsubscribe功能的函式或者物件
let ob = new Observable(obser => {
// 這個函式是“釋出”
obser.next()
})
// 訂閱了console.log(12)動作
ob.subscribe({
next(){console.log(12)}
})
注:只有subscribe方法執行了才會執行"釋出"函式
複製程式碼
在core-js
中已對observable
做了擴充套件,通過import "core-js/es7/observable"
可以使用Observable
實現Observable方法
便於理解,還是簡單的實現一個Observable
吧,程式碼如下
class SubscriptionObserver {
constructor(ob, debounceTime){
this.ob = ob || {};
this.debounceTime = debounceTime;
this.unSub = false;
this.timeout = null;
}
next(value){
if (!this.unSub && this.ob.next){
clearTimeout(this.timeout)
this.timeout = setTimeout(() => {
!this.unSub &&this.ob.next(value);
this.timeout = null;
}, this.debounceTime)
} else {
this.ob.next(value);
}
}
error(){
if (!this.unSub && this.ob.error){
this.ob.error();
}
}
complete(){
if (!this.unSub && this.complete){
this.ob.complete();
}
}
unsubcribe(){
this.unSub = true;
}
}
class Observable {
constructor(SubscriptionOb) {
this.SubscriptionOb = SubscriptionOb;
}
subscribe(ob){
this.subOb = new SubscriptionObserver(ob, this.timeout);
return this.SubscriptionOb(this.subOb);
}
unsubcribe(){
this.subOb.unsubcribe()
return this;
}
debounceTime(timeout){
this.timeout = timeout;
return this;
}
}
複製程式碼
主要增加了debounceTime功能, 在debounceTime在lazy時間內只會執行最後一次next方法
搜尋框的應用
搜尋框的搜尋主要是要解決2個問題
- 不能在使用者輸入每個字元的時候就觸發搜尋。
- 伺服器的非同步返回時間不一致,先搜尋的字元可能資料可能返回比後搜尋的慢
程式碼如下
export default class Tudos extends React.Component {
state = {
text:""
}
// 搜尋關鍵字介面
searchKeyWords(text){
return new Promise((resolve) => {
setTimeout(() => {
let list = [{...}...]
resolve(list)
}, 2000)
})
}
handleInput(dom) {
let oba = new Observable(ob => {
dom.oninput = e => {
ob.next(e.target.value)
}
}).debounceTime(500).subscribe({
next(value){getList(value)}
})
}
render() {
return (<div>
<input ref = {dom => dom && this.handleInput(dom)}/>
</div>)
}
}
複製程式碼
總會在使用者輸入完500毫秒後執行next函式。這個上述程式碼已實現. 第二個問題還未解決!
引入RxJS
安裝
npm i @reactivex/rxjs --save;
複製程式碼
引入
import * as Rx from "@reactivex/rxjs";
複製程式碼
RxJS 當做是用來處理事件的Lodash .像這種複雜的事件處理第一個就是想到使用RxJS
具體的使用可以參考以下官方文件
程式碼如下
export default class SimpleSortableList extends Component {
componentDidMount() {
}
// 搜尋關鍵字介面
searchKeyWords(text){
return new Promise((resolve) => {
setTimeout(() => {
let list = [{...}...]
resolve(list)
}, 2000)
})
}
handleInput(button){
Rx.Observable.fromEvent(button, 'input')
.debounceTime(500)
.switchMap(e => {
return Rx.Observable.create(ob => {
this.searchKeyWords(e.target.value).then(res => {
ob.next(list)
})
});
})
.subscribe(text => console.log(text))
}
render() {
return (
<div className={prefix}>
<input ref = { dom => dom && this.handleInput(dom)} />
</div>
);
}
}
複製程式碼
- 通過debounceTime延遲返回結果
- 通過switchMap丟棄上一個未及時返回的結果
- 而且整個程式碼顯得如此短小精悍