通過Observable解決搜尋框問題
觀察者模式也叫釋出訂閱模式. 最經典的用法就是在事件監聽裡面.
<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 丟棄上一個未及時返回的結果
- 而且整個程式碼顯得如此短小精悍