Submit Search
Upload
Why Redux-Observable?
•
4 likes
•
800 views
Anna Su
Follow
2017/11/04(六) JSDC 分享 相關資訊:http://2017.jsdc.tw/agenda.html
Read less
Read more
Engineering
Report
Share
Report
Share
1 of 111
Download now
Download to read offline
Recommended
You will learn RxJS in 2017
You will learn RxJS in 2017
名辰 洪
Avoiding callback hell in Node js using promises
Avoiding callback hell in Node js using promises
Ankit Agarwal
Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.js
Piotr Pelczar
Callbacks, promises, generators - asynchronous javascript
Callbacks, promises, generators - asynchronous javascript
Łukasz Kużyński
Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016
Ben Lesh
The Promised Land (in Angular)
The Promised Land (in Angular)
Domenic Denicola
Service worker: discover the next web game changer
Service worker: discover the next web game changer
Sandro Paganotti
Rethink Async With RXJS
Rethink Async With RXJS
Ryan Anklam
Recommended
You will learn RxJS in 2017
You will learn RxJS in 2017
名辰 洪
Avoiding callback hell in Node js using promises
Avoiding callback hell in Node js using promises
Ankit Agarwal
Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.js
Piotr Pelczar
Callbacks, promises, generators - asynchronous javascript
Callbacks, promises, generators - asynchronous javascript
Łukasz Kużyński
Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016
Ben Lesh
The Promised Land (in Angular)
The Promised Land (in Angular)
Domenic Denicola
Service worker: discover the next web game changer
Service worker: discover the next web game changer
Sandro Paganotti
Rethink Async With RXJS
Rethink Async With RXJS
Ryan Anklam
Asynchronní programování
Asynchronní programování
PeckaDesign.cz
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
Islam Sharabash
Asynchronous Programming FTW! 2 (with AnyEvent)
Asynchronous Programming FTW! 2 (with AnyEvent)
xSawyer
Correcting Common Async/Await Mistakes in .NET
Correcting Common Async/Await Mistakes in .NET
Brandon Minnick, MBA
Correcting Common .NET Async/Await Mistakes
Correcting Common .NET Async/Await Mistakes
Brandon Minnick, MBA
Angular server-side communication
Angular server-side communication
Alexe Bogdan
Expert JavaScript tricks of the masters
Expert JavaScript tricks of the masters
Ara Pehlivanian
Django Celery - A distributed task queue
Django Celery - A distributed task queue
Alex Eftimie
Debugging JavaScript with Chrome
Debugging JavaScript with Chrome
Igor Zalutsky
Angular promises and http
Angular promises and http
Alexe Bogdan
Automation in angular js
Automation in angular js
Marcin Wosinek
WebDriver Waits
WebDriver Waits
Yaroslav Pernerovsky
Implicit and Explicit waits in Selenium WebDriwer, how to.
Implicit and Explicit waits in Selenium WebDriwer, how to.
Yaroslav Pernerovsky
Any event intro
Any event intro
qiang
Automation puzzlers
Automation puzzlers
Yaroslav Pernerovsky
Practical Celery
Practical Celery
Cameron Maske
Mirage For Beginners
Mirage For Beginners
Wilson Su
Perl: Coro asynchronous
Perl: Coro asynchronous
Shmuel Fomberg
Introduction to Service Workers | Matteo Manchi
Introduction to Service Workers | Matteo Manchi
Codemotion
Scalable Angular 2 Application Architecture
Scalable Angular 2 Application Architecture
FDConf
Side effects-con-redux
Side effects-con-redux
Nicolas Quiceno Benavides
Advanced redux
Advanced redux
Boris Dinkevich
More Related Content
What's hot
Asynchronní programování
Asynchronní programování
PeckaDesign.cz
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
Islam Sharabash
Asynchronous Programming FTW! 2 (with AnyEvent)
Asynchronous Programming FTW! 2 (with AnyEvent)
xSawyer
Correcting Common Async/Await Mistakes in .NET
Correcting Common Async/Await Mistakes in .NET
Brandon Minnick, MBA
Correcting Common .NET Async/Await Mistakes
Correcting Common .NET Async/Await Mistakes
Brandon Minnick, MBA
Angular server-side communication
Angular server-side communication
Alexe Bogdan
Expert JavaScript tricks of the masters
Expert JavaScript tricks of the masters
Ara Pehlivanian
Django Celery - A distributed task queue
Django Celery - A distributed task queue
Alex Eftimie
Debugging JavaScript with Chrome
Debugging JavaScript with Chrome
Igor Zalutsky
Angular promises and http
Angular promises and http
Alexe Bogdan
Automation in angular js
Automation in angular js
Marcin Wosinek
WebDriver Waits
WebDriver Waits
Yaroslav Pernerovsky
Implicit and Explicit waits in Selenium WebDriwer, how to.
Implicit and Explicit waits in Selenium WebDriwer, how to.
Yaroslav Pernerovsky
Any event intro
Any event intro
qiang
Automation puzzlers
Automation puzzlers
Yaroslav Pernerovsky
Practical Celery
Practical Celery
Cameron Maske
Mirage For Beginners
Mirage For Beginners
Wilson Su
Perl: Coro asynchronous
Perl: Coro asynchronous
Shmuel Fomberg
Introduction to Service Workers | Matteo Manchi
Introduction to Service Workers | Matteo Manchi
Codemotion
Scalable Angular 2 Application Architecture
Scalable Angular 2 Application Architecture
FDConf
What's hot
(20)
Asynchronní programování
Asynchronní programování
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
Asynchronous Programming FTW! 2 (with AnyEvent)
Asynchronous Programming FTW! 2 (with AnyEvent)
Correcting Common Async/Await Mistakes in .NET
Correcting Common Async/Await Mistakes in .NET
Correcting Common .NET Async/Await Mistakes
Correcting Common .NET Async/Await Mistakes
Angular server-side communication
Angular server-side communication
Expert JavaScript tricks of the masters
Expert JavaScript tricks of the masters
Django Celery - A distributed task queue
Django Celery - A distributed task queue
Debugging JavaScript with Chrome
Debugging JavaScript with Chrome
Angular promises and http
Angular promises and http
Automation in angular js
Automation in angular js
WebDriver Waits
WebDriver Waits
Implicit and Explicit waits in Selenium WebDriwer, how to.
Implicit and Explicit waits in Selenium WebDriwer, how to.
Any event intro
Any event intro
Automation puzzlers
Automation puzzlers
Practical Celery
Practical Celery
Mirage For Beginners
Mirage For Beginners
Perl: Coro asynchronous
Perl: Coro asynchronous
Introduction to Service Workers | Matteo Manchi
Introduction to Service Workers | Matteo Manchi
Scalable Angular 2 Application Architecture
Scalable Angular 2 Application Architecture
Similar to Why Redux-Observable?
Side effects-con-redux
Side effects-con-redux
Nicolas Quiceno Benavides
Advanced redux
Advanced redux
Boris Dinkevich
Prescribing RX Responsibly
Prescribing RX Responsibly
Nareg Khoshafian
An Emoji Introduction to React Native (Panagiotis Vourtsis, Senior Front End ...
An Emoji Introduction to React Native (Panagiotis Vourtsis, Senior Front End ...
GreeceJS
Migrating from Flux to Redux. Why and how.
Migrating from Flux to Redux. Why and how.
Astrails
Bulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & Couchbase
Alex Derkach
Fact, Fiction, and FP
Fact, Fiction, and FP
Brian Lonsdorf
Solving anything in VCL
Solving anything in VCL
Fastly
ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015
Michiel Borkent
Android Best Practices
Android Best Practices
Yekmer Simsek
Chromium Embedded Framework + Go at Brooklyn JS
Chromium Embedded Framework + Go at Brooklyn JS
quirkey
Recompacting your react application
Recompacting your react application
Greg Bergé
When symfony met promises
When symfony met promises
Marc Morera
How and why i roll my own node.js framework
How and why i roll my own node.js framework
Ben Lin
Compose Async with RxJS
Compose Async with RxJS
Kyung Yeol Kim
Solr @ Etsy - Apache Lucene Eurocon
Solr @ Etsy - Apache Lucene Eurocon
Giovanni Fernandez-Kincade
[JEEConf-2017] RxJava as a key component in mature Big Data product
[JEEConf-2017] RxJava as a key component in mature Big Data product
Igor Lozynskyi
Headless Js Testing
Headless Js Testing
Brian Moschel
Apache Spark in your likeness - low and high level customization
Apache Spark in your likeness - low and high level customization
Bartosz Konieczny
Reactive Programming - ReactFoo 2020 - Aziz Khambati
Reactive Programming - ReactFoo 2020 - Aziz Khambati
Aziz Khambati
Similar to Why Redux-Observable?
(20)
Side effects-con-redux
Side effects-con-redux
Advanced redux
Advanced redux
Prescribing RX Responsibly
Prescribing RX Responsibly
An Emoji Introduction to React Native (Panagiotis Vourtsis, Senior Front End ...
An Emoji Introduction to React Native (Panagiotis Vourtsis, Senior Front End ...
Migrating from Flux to Redux. Why and how.
Migrating from Flux to Redux. Why and how.
Bulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & Couchbase
Fact, Fiction, and FP
Fact, Fiction, and FP
Solving anything in VCL
Solving anything in VCL
ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015
Android Best Practices
Android Best Practices
Chromium Embedded Framework + Go at Brooklyn JS
Chromium Embedded Framework + Go at Brooklyn JS
Recompacting your react application
Recompacting your react application
When symfony met promises
When symfony met promises
How and why i roll my own node.js framework
How and why i roll my own node.js framework
Compose Async with RxJS
Compose Async with RxJS
Solr @ Etsy - Apache Lucene Eurocon
Solr @ Etsy - Apache Lucene Eurocon
[JEEConf-2017] RxJava as a key component in mature Big Data product
[JEEConf-2017] RxJava as a key component in mature Big Data product
Headless Js Testing
Headless Js Testing
Apache Spark in your likeness - low and high level customization
Apache Spark in your likeness - low and high level customization
Reactive Programming - ReactFoo 2020 - Aziz Khambati
Reactive Programming - ReactFoo 2020 - Aziz Khambati
More from Anna Su
Clean Architecture
Clean Architecture
Anna Su
2017 台灣成長駭客年會 與會心得分享
2017 台灣成長駭客年會 與會心得分享
Anna Su
PWA 應用與價值
PWA 應用與價值
Anna Su
初探 DevOps 的世界
初探 DevOps 的世界
Anna Su
NASA hackathon - Sea More
NASA hackathon - Sea More
Anna Su
用 Javascript 實現你的想像
用 Javascript 實現你的想像
Anna Su
PWA 應用 - 實現網站離線瀏覽
PWA 應用 - 實現網站離線瀏覽
Anna Su
網站建置流程
網站建置流程
Anna Su
網站建置初探
網站建置初探
Anna Su
PWA 與 Service Worker
PWA 與 Service Worker
Anna Su
2016 PIXNET HACKATHON Lightning talk - 做網站不是只有一個人的事
2016 PIXNET HACKATHON Lightning talk - 做網站不是只有一個人的事
Anna Su
從一個超簡單範例開始學習 Canvas
從一個超簡單範例開始學習 Canvas
Anna Su
Rucksack 裝滿神奇 css 的後背包
Rucksack 裝滿神奇 css 的後背包
Anna Su
CSS modules 簡單玩
CSS modules 簡單玩
Anna Su
Trello - 規劃工作與生活的管理工具
Trello - 規劃工作與生活的管理工具
Anna Su
webpack 入門
webpack 入門
Anna Su
入門Gulp - 前端自動化開發工具
入門Gulp - 前端自動化開發工具
Anna Su
幸福快樂的完美結局
幸福快樂的完美結局
Anna Su
偷呷步的網站快速入門
偷呷步的網站快速入門
Anna Su
調配網站的明星花露水
調配網站的明星花露水
Anna Su
More from Anna Su
(20)
Clean Architecture
Clean Architecture
2017 台灣成長駭客年會 與會心得分享
2017 台灣成長駭客年會 與會心得分享
PWA 應用與價值
PWA 應用與價值
初探 DevOps 的世界
初探 DevOps 的世界
NASA hackathon - Sea More
NASA hackathon - Sea More
用 Javascript 實現你的想像
用 Javascript 實現你的想像
PWA 應用 - 實現網站離線瀏覽
PWA 應用 - 實現網站離線瀏覽
網站建置流程
網站建置流程
網站建置初探
網站建置初探
PWA 與 Service Worker
PWA 與 Service Worker
2016 PIXNET HACKATHON Lightning talk - 做網站不是只有一個人的事
2016 PIXNET HACKATHON Lightning talk - 做網站不是只有一個人的事
從一個超簡單範例開始學習 Canvas
從一個超簡單範例開始學習 Canvas
Rucksack 裝滿神奇 css 的後背包
Rucksack 裝滿神奇 css 的後背包
CSS modules 簡單玩
CSS modules 簡單玩
Trello - 規劃工作與生活的管理工具
Trello - 規劃工作與生活的管理工具
webpack 入門
webpack 入門
入門Gulp - 前端自動化開發工具
入門Gulp - 前端自動化開發工具
幸福快樂的完美結局
幸福快樂的完美結局
偷呷步的網站快速入門
偷呷步的網站快速入門
調配網站的明星花露水
調配網站的明星花露水
Recently uploaded
Correctly Loading Incremental Data at Scale
Correctly Loading Incremental Data at Scale
Alluxio, Inc.
Call Us -/9953056974- Call Girls In Vikaspuri-/- Delhi NCR
Call Us -/9953056974- Call Girls In Vikaspuri-/- Delhi NCR
9953056974 Low Rate Call Girls In Saket, Delhi NCR
Electronically Controlled suspensions system .pdf
Electronically Controlled suspensions system .pdf
me23b1001
Past, Present and Future of Generative AI
Past, Present and Future of Generative AI
abhishek36461
CCS355 Neural Network & Deep Learning Unit II Notes with Question bank .pdf
CCS355 Neural Network & Deep Learning Unit II Notes with Question bank .pdf
Asst.prof M.Gokilavani
Application of Residue Theorem to evaluate real integrations.pptx
Application of Residue Theorem to evaluate real integrations.pptx
959SahilShah
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsync
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsync
ssuser2ae721
Churning of Butter, Factors affecting .
Churning of Butter, Factors affecting .
Satyam Kumar
What are the advantages and disadvantages of membrane structures.pptx
What are the advantages and disadvantages of membrane structures.pptx
wendy cai
Arduino_CSE ece ppt for working and principal of arduino.ppt
Arduino_CSE ece ppt for working and principal of arduino.ppt
SAURABHKUMAR892774
Call Girls Delhi {Jodhpur} 9711199012 high profile service
Call Girls Delhi {Jodhpur} 9711199012 high profile service
rehmti665
TechTAC® CFD Report Summary: A Comparison of Two Types of Tubing Anchor Catchers
TechTAC® CFD Report Summary: A Comparison of Two Types of Tubing Anchor Catchers
sdickerson1
young call girls in Rajiv Chowk🔝 9953056974 🔝 Delhi escort Service
young call girls in Rajiv Chowk🔝 9953056974 🔝 Delhi escort Service
9953056974 Low Rate Call Girls In Saket, Delhi NCR
🔝9953056974🔝!!-YOUNG call girls in Rajendra Nagar Escort rvice Shot 2000 nigh...
🔝9953056974🔝!!-YOUNG call girls in Rajendra Nagar Escort rvice Shot 2000 nigh...
9953056974 Low Rate Call Girls In Saket, Delhi NCR
Architect Hassan Khalil Portfolio for 2024
Architect Hassan Khalil Portfolio for 2024
hassan khalil
Gurgaon ✡️9711147426✨Call In girls Gurgaon Sector 51 escort service
Gurgaon ✡️9711147426✨Call In girls Gurgaon Sector 51 escort service
jennyeacort
INFLUENCE OF NANOSILICA ON THE PROPERTIES OF CONCRETE
INFLUENCE OF NANOSILICA ON THE PROPERTIES OF CONCRETE
roselinkalist12
Exploring_Network_Security_with_JA3_by_Rakesh Seal.pptx
Exploring_Network_Security_with_JA3_by_Rakesh Seal.pptx
null - The Open Security Community
IVE Industry Focused Event - Defence Sector 2024
IVE Industry Focused Event - Defence Sector 2024
Mark Billinghurst
POWER SYSTEMS-1 Complete notes examples
POWER SYSTEMS-1 Complete notes examples
Dr. Gudipudi Nageswara Rao
Recently uploaded
(20)
Correctly Loading Incremental Data at Scale
Correctly Loading Incremental Data at Scale
Call Us -/9953056974- Call Girls In Vikaspuri-/- Delhi NCR
Call Us -/9953056974- Call Girls In Vikaspuri-/- Delhi NCR
Electronically Controlled suspensions system .pdf
Electronically Controlled suspensions system .pdf
Past, Present and Future of Generative AI
Past, Present and Future of Generative AI
CCS355 Neural Network & Deep Learning Unit II Notes with Question bank .pdf
CCS355 Neural Network & Deep Learning Unit II Notes with Question bank .pdf
Application of Residue Theorem to evaluate real integrations.pptx
Application of Residue Theorem to evaluate real integrations.pptx
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsync
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsync
Churning of Butter, Factors affecting .
Churning of Butter, Factors affecting .
What are the advantages and disadvantages of membrane structures.pptx
What are the advantages and disadvantages of membrane structures.pptx
Arduino_CSE ece ppt for working and principal of arduino.ppt
Arduino_CSE ece ppt for working and principal of arduino.ppt
Call Girls Delhi {Jodhpur} 9711199012 high profile service
Call Girls Delhi {Jodhpur} 9711199012 high profile service
TechTAC® CFD Report Summary: A Comparison of Two Types of Tubing Anchor Catchers
TechTAC® CFD Report Summary: A Comparison of Two Types of Tubing Anchor Catchers
young call girls in Rajiv Chowk🔝 9953056974 🔝 Delhi escort Service
young call girls in Rajiv Chowk🔝 9953056974 🔝 Delhi escort Service
🔝9953056974🔝!!-YOUNG call girls in Rajendra Nagar Escort rvice Shot 2000 nigh...
🔝9953056974🔝!!-YOUNG call girls in Rajendra Nagar Escort rvice Shot 2000 nigh...
Architect Hassan Khalil Portfolio for 2024
Architect Hassan Khalil Portfolio for 2024
Gurgaon ✡️9711147426✨Call In girls Gurgaon Sector 51 escort service
Gurgaon ✡️9711147426✨Call In girls Gurgaon Sector 51 escort service
INFLUENCE OF NANOSILICA ON THE PROPERTIES OF CONCRETE
INFLUENCE OF NANOSILICA ON THE PROPERTIES OF CONCRETE
Exploring_Network_Security_with_JA3_by_Rakesh Seal.pptx
Exploring_Network_Security_with_JA3_by_Rakesh Seal.pptx
IVE Industry Focused Event - Defence Sector 2024
IVE Industry Focused Event - Defence Sector 2024
POWER SYSTEMS-1 Complete notes examples
POWER SYSTEMS-1 Complete notes examples
Why Redux-Observable?
1.
Why Redux-Observable? JSDC 2017/11/04
2.
2
3.
3
4.
通常我們如何在 Redux 處理理 非同步問題?
5.
5 Redux-thunk
6.
6 Redux-thunk redux 專案⼤大多使⽤用 redux-thunk
處理理非同步問題
7.
為什什麼不繼續使⽤用 Redux-thunk 7 ?
8.
我們來來想想... 實務上我們可能會遇到哪些問題? 8
9.
PM 跟你說:網站要做 搜尋
功能 9 ‣ 顯⽰示搜尋結果 ‣ 記錄關鍵字 History
10.
如果使⽤用 redux-thunk 我們來來看程式碼可能會怎麼寫... 10 ?
11.
搜尋功能 你可能會這樣寫... 11 let controller; export const
search = keyword !=> dispatch !=> { if (!keyword) { return; } dispatch({ type: SEARCH_REQUEST}); if (controller) { controller.abort(); } controller = new AbortController(); return fetch(`/search?k=${keyword}`, { signal: controller.signal, }).then(res !=> { dispatch(receiveSearchResult(res)); dispatch(push(`/search/${keyword}`)); dispatch(addKeywordHistory(keyword)); controller = undefined; }); };
12.
搜尋功能 搜尋關鍵字必須有值, 才執⾏行行 request 12 let controller; export
const search = keyword !=> dispatch !=> { if (!keyword) { return; } dispatch({ type: SEARCH_REQUEST}); if (controller) { controller.abort(); }
13.
搜尋功能 回傳搜尋資料之前, 顯⽰示 Loading 動畫 13 let
controller; export const search = keyword !=> dispatch !=> { if (!keyword) { return; } dispatch({ type: SEARCH_REQUEST }); if (controller) { controller.abort(); } controller = new AbortController(); return fetch(`/search?k=${keyword}`, { signal: controller.signal,
14.
搜尋功能 GET API,取得搜尋資料 14 dispatch({ type:
SEARCH_REQUEST}); if (controller) { controller.abort(); } controller = new AbortController(); return fetch(`/search?k=${keyword}`, { signal: controller.signal, }).then(res !=> { dispatch(receiveSearchResult(res)); dispatch(push(`/search/${keyword}`)); dispatch(addKeywordHistory(keyword)); controller = undefined; }); };
15.
搜尋功能 觸發另外⼀一個 action 顯⽰示搜尋結果 15 dispatch({ type:
SEARCH_REQUEST}); if (controller) { controller.abort(); } controller = new AbortController(); return fetch(`/search?k=${keyword}`, { signal: controller.signal, }).then(res !=> { dispatch(receiveSearchResult(res)); dispatch(push(`/search/${keyword}`)); dispatch(addKeywordHistory(keyword)); controller = undefined; }); };
16.
搜尋功能 dispatch({ type: SEARCH_REQUEST}); if
(controller) { controller.abort(); } controller = new AbortController(); return fetch(`/search?k=${keyword}`, { signal: controller.signal, }).then(res !=> { dispatch(receiveSearchResult(res)); dispatch(push(`/search/${keyword}`)); dispatch(addKeywordHistory(keyword)); controller = undefined; }); }; 變更更網址 16
17.
搜尋功能 dispatch({ type: SEARCH_REQUEST}); if
(controller) { controller.abort(); } controller = new AbortController(); return fetch(`/search?k=${keyword}`, { signal: controller.signal, }).then(res !=> { dispatch(receiveSearchResult(res)); dispatch(push(`/search/${keyword}`)); dispatch(addKeywordHistory(keyword)); controller = undefined; }); }; 傳入關鍵字,記錄 History 17
18.
如何在 Redux-thunk 取消 request? 18
19.
如何在 Redux-thunk 取消 request? 19
20.
20
21.
搜尋功能 宣告 controller 變數 21 let
controller; export const search = keyword !=> dispatch !=> { if (!keyword) { return; } dispatch({ type: SEARCH_REQUEST}); if (controller) { controller.abort(); }
22.
搜尋功能 新增 controller 提供取消 request
的⽅方法 22 dispatch({ type: SEARCH_REQUEST}); if (controller) { controller.abort(); } controller = new AbortController(); return fetch(`/search?keyword=${keyword}&lim signal: controller.signal, }).then(res !=> { dispatch(receiveSearchResult(res)); dispatch(push(`/search/${keyword}`)); dispatch(addKeywordHistory(keyword)); controller = undefined; }); };
23.
搜尋功能 將舊的 request 取消, 執⾏行行新的
request 23 dispatch({ type: SEARCH_REQUEST}); if (controller) { controller.abort(); } controller = new AbortController(); return fetch(`/search?keyword=${keyword}&lim signal: controller.signal, }).then(res !=> { dispatch(receiveSearchResult(res)); dispatch(push(`/search/${keyword}`)); dispatch(addKeywordHistory(keyword)); controller = undefined; }); };
24.
搜尋功能 使⽤用 redux-thunk… 24 let controller; export
const search = keyword !=> dispatch !=> { if (!keyword) { return; } dispatch({ type: SEARCH_REQUEST}); if (controller) { controller.abort(); } controller = new AbortController(); return fetch(`/search?keyword=${keyword}&limit=20`, { signal: controller.signal, }).then(res !=> { dispatch(receiveSearchResult(res)); dispatch(push(`/search/${keyword}`)); dispatch(addKeywordHistory(keyword)); controller = undefined; }); };
25.
25 有沒有更更快速⼜又簡單的⽅方法? 幫我們解決這些常⾒見見的非同步問題
26.
26 redux-thunk redux-observable let controller; export
const search = keyword !=> dispatch !=> { if (!keyword) { return; } dispatch({ type: SEARCH_REQUEST}); if (controller) { controller.abort(); } controller = new AbortController(); return fetch(`/search?k=${keyword}`, { signal: controller.signal, }).then(res !=> { dispatch(receiveSearchResult(res)); dispatch(push(`/search/${keyword}`)); dispatch(addKeywordHistory(keyword)); controller = undefined; }); }; export const searchEpic = action$ !=> action$ .ofType(SEARCH_REQUEST) .filter(action !=> action.payload) .switchMap(getSearchResult) .mergeMap(res !=> Observable.of( receiveSearchResult(res.data), push(`/search/${res.keyword}`), addSearchHistory(res.keyword) ) );
27.
27 let controller; export const
search = keyword !=> dispatch !=> { if (!keyword) { return; } dispatch({ type: SEARCH_REQUEST}); if (controller) { controller.abort(); } controller = new AbortController(); return fetch(`/search?k=${keyword}`, { signal: controller.signal, }).then(res !=> { dispatch(receiveSearchResult(res)); dispatch(push(`/search/${keyword}`)); dispatch(addKeywordHistory(keyword)); controller = undefined; }); }; export const searchEpic = action$ !=> action$ .ofType(SEARCH_REQUEST) .filter(action !=> action.payload) .switchMap(getSearchResult) .mergeMap(res !=> Observable.of( receiveSearchResult(res.data), push(`/search/${res.keyword}`), addSearchHistory(res.keyword) ) ); 25⾏行行程式碼 12⾏行行程式碼 程式碼 少了了 1/2 redux-observable ⼤大約
28.
28 let controller; export const
search = keyword !=> dispatch !=> { if (!keyword) { return; } dispatch({ type: SEARCH_REQUEST}); if (controller) { controller.abort(); } controller = new AbortController(); return fetch(`/search?k=${keyword}`, { signal: controller.signal, }).then(res !=> { dispatch(receiveSearchResult(res)); dispatch(push(`/search/${keyword}`)); dispatch(addKeywordHistory(keyword)); controller = undefined; }); }; export const searchEpic = action$ !=> action$ .ofType(SEARCH_REQUEST) .filter(action !=> action.payload) .switchMap(getSearchResult) .mergeMap(res !=> Observable.of( receiveSearchResult(res.data), push(`/search/${res.keyword}`), addSearchHistory(res.keyword) ) ); 有 if 判斷 沒有 if 判斷 程式碼 容易易閱讀 redux-observable 比較
29.
29 let controller; export const
search = keyword !=> dispatch !=> { if (!keyword) { return; } dispatch({ type: SEARCH_REQUEST}); if (controller) { controller.abort(); } controller = new AbortController(); return fetch(`/search?k=${keyword}`, { signal: controller.signal, }).then(res !=> { dispatch(receiveSearchResult(res)); dispatch(push(`/search/${keyword}`)); dispatch(addKeywordHistory(keyword)); controller = undefined; }); }; export const searchEpic = action$ !=> action$ .ofType(SEARCH_REQUEST) .filter(action !=> action.payload) .switchMap(getSearchResult) .mergeMap(res !=> Observable.of( receiveSearchResult(res.data), push(`/search/${res.keyword}`), addSearchHistory(res.keyword) ) ); 只⽀支援 firefox 57 版 只有 IE 10 以下不⽀支援 有效率的完成功能 redux-observable
30.
30 好像還不錯?! Redux-Observable Redux-Observable
31.
What’s Redux-Observable?
32.
RxJS 5-based middleware
for Redux 32
33.
33 Store dispatch Reducer Action Middleware Component State
34.
34 Store dispatch Reducer Action Middleware Component State
35.
35 Store dispatch Reducer Action Middleware Component State
36.
36 Store dispatch Reducer Action Middleware Component State
37.
37 Store dispatch epic epic epic
epicepic redux-observable Reducer Action State
38.
38 Store dispatch epic epic epic
epicepic redux-observable Reducer Action State
39.
39 Store dispatch epic epic epic
epicepic redux-observable Reducer Action State
40.
export const openToastEpic
= action$ !=> { return action$ .ofType(OPEN_TOAST) .delay(3000) .mapTo({ type: CLOSE_TOAST }); }; Epic 40
41.
export const openToastEpic
= action$ !=> { return action$ .ofType(OPEN_TOAST) .delay(3000) .mapTo({ type: CLOSE_TOAST }); }; Epic 41
42.
export const openToastEpic
= action$ !=> { return action$ .ofType(OPEN_TOAST) .delay(3000) .mapTo({ type: CLOSE_TOAST }); }; Epic 42
43.
43 epic epic epic
epicepic
44.
epic epic epic
epicepic rootEpic 44
45.
rootEpic.js 45 import { combineEpics
} from 'redux-observable'; import { openToastEpic } from './toastStatus.js'; import { checkEmailEpic } from './emailCheckStatus.js'; import { searchEpic } from './search.js'; import { getArticlesEpic } from './articles.js'; export default combineEpics( openToastEpic, checkEmailEpic, searchEpic, getArticlesEpic );
46.
index.js 46 … const store =
createStore( reducer, applyMiddleware(createEpicMiddleware(rootEpics)) ); … Store Middleware Reducer
47.
index.js 47 … const store =
createStore( reducer, applyMiddleware(createEpicMiddleware(rootEpics)) ); … Store Middleware Reducer
48.
index.js 48 … const store =
createStore( reducer, applyMiddleware(createEpicMiddleware(rootEpics)) ); … Store Middleware Reducer
49.
49
50.
50 訊息通知
51.
51 按下確定按鈕
52.
52 open toast
53.
53
54.
訊息通知 按下按鈕 觸發 action creator 54 <button
onClick={openToast}>確定#</button>
55.
訊息通知 建立 action creator
和 epic 55 export const openToast = () !=> ({ type: OPEN_TOAST, }); export const openToastEpic = action$ !=> { return action$ .ofType(OPEN_TOAST) .delay(3000) .mapTo({ type: CLOSE_TOAST }); };
56.
訊息通知 傳入 action observable 56 export
const openToastEpic = action$ !=> { return action$ .ofType(OPEN_TOAST) .delay(3000) .mapTo({ type: CLOSE_TOAST }); };
57.
訊息通知 過濾出對應的 action type 57 export
const openToastEpic = action$ !=> { return action$ .ofType(OPEN_TOAST) .delay(3000) .mapTo({ type: CLOSE_TOAST }); };
58.
訊息通知 delay 3 秒 58 export
const openToastEpic = action$ !=> { return action$ .ofType(OPEN_TOAST) .delay(3000) .mapTo({ type: CLOSE_TOAST }); };
59.
訊息通知 觸發關閉 Toast 的
action 59 export const openToastEpic = action$ !=> { return action$ .ofType(OPEN_TOAST) .delay(3000) .mapTo({ type: CLOSE_TOAST }); };
60.
訊息通知 到 reducer、更更新 state 改變
store 60 export default function toastStatus(state = false, action) { switch (action.type) { case OPEN_TOAST: return true; case CLOSE_TOAST: return false; default: return state; } }
61.
訊息通知 到 reducer、更更新 state 改變
store 61 export default function toastStatus(state = false, action) { switch (action.type) { case OPEN_TOAST: return true; case CLOSE_TOAST: return false; default: return state; } }
62.
訊息通知 UI 發⽣生改變 62 <div className={classNames('toast',
{ show })}> <p>儲存成功!#</p> #</div>
63.
Redux-Observable use case
64.
64 E-mail 即時驗證 載入更更多⽂文章 Redux-Observable
use case
65.
65 E-mail 即時驗證
66.
66
67.
67
68.
68 取消舊的 request,執⾏行行新的 request
69.
Email 即時驗證 export const
checkEmailEpic = actions !=> { return actions .ofType(CHECK_EMAIL) .debounceTime(500) .switchMap(checkEmailIsUnique) .map(receiveEmailStatus); }; 過濾出對應的 action type 69
70.
Email 即時驗證 export const
checkEmailEpic = actions !=> { return actions .ofType(CHECK_EMAIL) .debounceTime(500) .switchMap(checkEmailIsUnique) .map(receiveEmailStatus); }; 觸發後,靜置500毫秒 70
71.
Email 即時驗證 export const
checkEmailEpic = actions !=> { return actions .ofType(CHECK_EMAIL) .debounceTime(500) .filter(validateEmail) .switchMap(checkEmailIsUnique) .map(receiveEmailStatus); }; 觸發後,靜置500毫秒才做驗證 71 通常⽤用在輸入框 靜置⼀一段時間才觸發 debounceTime
72.
Email 即時驗證 export const
checkEmailEpic = actions !=> { return actions .ofType(CHECK_EMAIL) .debounceTime(500) .switchMap(checkEmailIsUnique) .map(receiveEmailStatus); }; 接收最新的 request, 舊的 request 都取消 72
73.
Email 即時驗證 export const
checkEmailEpic = actions !=> { return actions .ofType(CHECK_EMAIL) .debounceTime(500) .filter(validateEmail) .switchMap(checkEmailIsUnique) .map(receiveEmailStatus); }; 取最新的 request, 舊的 request 都取消 73 取消舊的 request,執⾏行行新的 request switchMap 情境1: 表單即時驗證 情境2: Autocomplete 的輸入框
74.
Email 即時驗證 export const
checkEmailEpic = actions !=> { return actions .ofType(CHECK_EMAIL) .debounceTime(500) .switchMap(checkEmailIsUnique) .map(receiveEmailStatus); }; 獲取 Email 狀狀態 74
75.
75 ㄈ
76.
Email 即時驗證 export const
checkEmailEpic = actions !=> { return actions .ofType(CHECK_EMAIL) .debounceTime(500) .filter(validateEmail) .switchMap(checkEmailIsUnique) .map(receiveEmailStatus); }; Email 格式正確才發 request 76
77.
Email 即時驗證 export const
checkEmailEpic = actions !=> { return actions .ofType(CHECK_EMAIL) .debounceTime(500) .filter(validateEmail) .switchMap(checkEmailIsUnique) .map(receiveEmailStatus); }; 觸發後,靜置500毫秒才做驗證 77 快速輕鬆的完成功能 不需要會 RxJS,就可以使⽤用 operator
78.
78 載入更更多⽂文章
79.
79
80.
過濾出對應的 action type 80 export
const getArticlesEpic = action$ !=> { return action$ .ofType(GET_ARTICLES) .exhaustMap(getArticlesAPI) .map(receiveArticles); }; 載入更更多⽂文章
81.
取原本送出的 request, 新的 request
都取消 81 export const getArticlesEpic = action$ !=> { return action$ .ofType(GET_ARTICLES) .exhaustMap(getArticlesAPI) .map(receiveArticles); }; 載入更更多⽂文章
82.
82 無限滾動⽂文章
83.
83
84.
無限滾動⽂文章 export const getArticlesEpic
= action$ !=> { return action$ .ofType(GET_ARTICLES) .exhaustMap(getArticlesAPI) .map(receiveArticles); }; 取原本送出的 request, 新的 request 都取消 84
85.
Email 即時驗證 export const
checkEmailEpic = actions !=> { return actions .ofType(CHECK_EMAIL) .debounceTime(500) .filter(validateEmail) .switchMap(checkEmailIsUnique) .map(receiveEmailStatus); }; 取最新的 request, 舊的 request 都取消 85 取原本送出的 request,新的 request 都取消 exhaustMap 情境1: 看更更多⽂文章 情境2: 上傳檔案
86.
export const getArticlesEpic
= actions !=> { return actions .ofType(GET_ARTICLES) .throttleTime(100) .exhaustMap(getArticlesAPI) .map(receiveArticles); }; 無限滾動⽂文章 throttle 100 毫秒 才送 request 86
87.
Email 即時驗證 export const
checkEmailEpic = actions !=> { return actions .ofType(CHECK_EMAIL) .debounceTime(500) .filter(validateEmail) .switchMap(checkEmailIsUnique) .map(receiveEmailStatus); }; 觸發後,靜置500毫秒才做驗證 87 通常⽤用在連續性⾏行行為 throttleTime 情境1: 滾動事件 情境2: 拖拉事件 避免⾼高頻率觸發
88.
Email 即時驗證 export const
checkEmailEpic = actions !=> { return actions .ofType(CHECK_EMAIL) .debounceTime(500) .filter(validateEmail) .switchMap(checkEmailIsUnique) .map(receiveEmailStatus); }; 觸發後,靜置500毫秒才做驗證 88 重⽤用性與可讀性提昇 組合使⽤用 operator
89.
Email 即時驗證 export const
checkEmailEpic = actions !=> { return actions .ofType(CHECK_EMAIL) .debounceTime(500) .filter(validateEmail) .switchMap(checkEmailIsUnique) .map(receiveEmailStatus); }; 觸發後,靜置500毫秒才做驗證 89 優雅的解決非同步問題 簡單使⽤用 operator
90.
你不需要會 RxJS, 就可以直接使⽤用 Redux-Observable
! 90
91.
91
92.
Compare with other middleware
?
93.
93 13 Jul 2015 redux-thunk
redux-saga 3 Dec 2015 redux-observable 21 Apr 2016 redux-cycle 3 Dec 2016 2017/10/23 Redux middlewares
94.
redux-thunk redux-observable 94 export const
openPopup = () !=> dispatch !=> { dispatch({ type: OPEN_POPUP, }); setTimeout(() !=> { dispatch({ type: CLOSE_POPUP, }); }, 3000); }; export const openPopupEpic = action$ !=> { return action$ .ofType(OPEN_POPUP) .delay(3000) .mapTo({ type: CLOSE_POPUP }); };
95.
redux-thunk •容易易上⼿手 •程式碼冗長 •不易易閱讀 •難以維護 95 export const openPopup
= () !=> dispatch !=> { dispatch({ type: OPEN_POPUP, }); setTimeout(() !=> { dispatch({ type: CLOSE_POPUP, }); }, 3000); };
96.
redux-saga redux-observable 96 export function*
openPopupAsync () { yield call(delay, 3000) yield put({ type: 'CLOSE_POPUP' }) } export function* watchOpenPopupAsync () { yield takeEvery('OPEN_POPUP', openPopupAsync) } export const openPopupEpic = action$ !=> { return action$ .ofType(OPEN_POPUP) .delay(3000) .mapTo({ type: CLOSE_POPUP }); };
97.
redux-saga •技術不能轉移 •依賴 syntax (Generator) 97 export
function* openPopupAsync () { yield call(delay, 3000) yield put({ type: 'CLOSE_POPUP' }) } export function* watchOpenPopupAsync () { yield takeEvery('OPEN_POPUP', openPopupAsync) } •可以處理理較複雜的非同步問題 •星星數較多,使⽤用社群較⼤大
98.
redux-cycles redux-observable 98 export const
openPopupEpic = action$ !=> { return action$ .ofType(OPEN_POPUP) .delay(3000) .mapTo({ type: CLOSE_POPUP }); }; function openPopup (sources) { const openPopup$ = sources.ACTION .filter(action !=> action.type &&=== OPEN_POPUP) .delay(3000) .mapTo({ type: CLOSE_POPUP }); return { ACTION: openPopup$ } }
99.
redux-cycles redux-observable 99 function fetchUserData(sources)
{ const request$ = sources.ACTION .filter(action !=> action.type &&=== FETCH_USER) .map(action !=> ({ url: `${API_URL}users/`, category: 'users', })); const action$ = sources.HTTP .select('users') .flatten() .map(fetchUserFulfilled); return { ACTION: action$, HTTP: request$, }; } const fetchUserDataEpic = action$ !=> action$ .ofType(FETCH_USER) .mergeMap(action !=> ajax.getJSON(`${API_URL}users/`) .map(fetchUserFulfilled) );
100.
redux-cycle •社群⼈人數較少 •過度封裝? 100 function fetchUserData(sources) { const
request$ = sources.ACTION .filter(action !=> action.type &&=== FETCH_USER) .map(action !=> ({ url: `${API_URL}users/`, category: 'users', })); const action$ = sources.HTTP .select('users') .flatten() .map(fetchUserFulfilled); return { ACTION: action$, HTTP: request$, }; } •可以處理理較複雜的 非同步問題
101.
101 redux-thunk redux-saga redux-cycle
redux-observable 程式碼簡潔 處理複雜的⾮同步情境 技術可轉移 Why Redux-Observable?
102.
102 redux-thunk redux-saga redux-cycle
redux-observable 程式碼簡潔 處理複雜的⾮同步情境 技術可轉移 Why Redux-Observable?
103.
(你應該學習 Observable 的原因) 103 技術可轉移 RxJava RxPHP 將成為
ECMAScript 標準 Stage1 前端框架都有 Observable Redux-Observable vue-rx Angular2 之後RxSwift Why Redux-Observable?
104.
104 ‣ 程式碼更更簡潔 ‣ 可讀性更更⾼高 ‣
容易易寫測試 ‣ 更更快速完成功能 Why Redux-Observable?
105.
105
106.
106
107.
107
108.
108
109.
Reference ‣ https://redux-observable.js.org/ ‣ https://github.com/redux-observable/redux-observable ‣
http://reactivex.io/languages.html ‣ https://github.com/reactjs/redux/issues/1461#issuecomment-190165193 ‣ https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort ‣ https://twitter.com/dan_abramov/status/816244945015160832 109
110.
Image Credit ‣ http://oreilly-generator.com/ ‣
http://renzhou.tw/yinwubrother-textmaker/ ‣ https://www.flaticon.com/packs/emoji-6 ‣ https://www.flaticon.com/packs/design-35 110
111.
Thank you :D
Download now