SlideShare a Scribd company logo
1 of 98
Download to read offline
RxJS + Redux + React = Amazing
Jay Phelps | @_jayphelps
Side Effect Management with RxJS
Jay Phelps | @_jayphelps
Managing state stuff is hard
Jay Phelps | @_jayphelps
Redux makes it simple
(not necessarily easy)
Jay Phelps | @_jayphelps
Managing async stuff is harder
Jay Phelps | @_jayphelps
Some async is complex regardless
of the abstraction
Jay Phelps | @_jayphelps
RxJS makes it manageable
Jay Phelps
Senior Software Engineer |
@_jayphelps
What is redux?
Jay Phelps | @_jayphelps
Crash Course
Jay Phelps | @_jayphelps
What is redux?
Jay Phelps | @_jayphelps
Provides predicable state management using
actions and reducers
What's an "action"?
Jay Phelps | @_jayphelps
Describes something has (or should) happen, but
they don't specify how it should be done
Jay Phelps | @_jayphelps
{	
		type:	'CREATE_TODO',	
		payload:	'Build	my	first	Redux	app'	
}
What's an "reducer"?
Jay Phelps | @_jayphelps
A pure function that takes the previous state
and an action and returns the new state
What's an "reducer"?
Jay Phelps | @_jayphelps
Sometimes it returns the previous state
(state,	action)	=>	state
What's an "reducer"?
Jay Phelps | @_jayphelps
Sometimes it computes new state
(state,	action)	=>	state	+	action.payload
Jay Phelps | @_jayphelps
const	counter	=	(state	=	0,	action)	=>	{	
		switch	(action.type)	{	
				case	'INCREMENT':	
						return	state	+	1;	
				case	'DECREMENT':	
						return	state	-	1;	
						
				default:	
						return	state;	
		}	
};
Jay Phelps | @_jayphelps
Reducers handle state transitions, but they
must be done synchronously.
Jay Phelps | @_jayphelps
const	counter	=	(state	=	0,	action)	=>	{	
		switch	(action.type)	{	
				case	'INCREMENT':	
						return	state	+	1;	
				case	'DECREMENT':	
						return	state	-	1;	
						
				default:	
						return	state;	
		}	
};
Jay Phelps | @_jayphelps
What are async stuff do we commonly do?
Async
Jay Phelps | @_jayphelps
• User interactions (mouse, keyboard, etc)
• AJAX
• Timers/Animations
• Web Sockets
• Work Workers, etc
Jay Phelps | @_jayphelps
Some can be handled synchronously
Jay Phelps | @_jayphelps
<button	onClick={()	=>	dispatch({	type:	'INCREMENT'	})}>	
		Increment	
</button>
Jay Phelps | @_jayphelps
const	counter	=	(state	=	0,	action)	=>	{	
		switch	(action.type)	{	
				case	'INCREMENT':	
						return	state	+	1;	
				case	'DECREMENT':	
						return	state	-	1;	
						
				default:	
						return	state;	
		}	
};
Jay Phelps | @_jayphelps
Sometimes you need more control
Jay Phelps | @_jayphelps
• AJAX cancellation/composing
• Debounce/throttle/buffer/etc
• Drag and Drop
• Web Sockets, Work Workers, etc
Jay Phelps | @_jayphelps
Use middleware to manage async / side effects
Jay Phelps | @_jayphelps
Most of them use callbacks or Promises
Callbacks
Jay Phelps | @_jayphelps
The most primitive way to handle async in JavaScript
Callbacks
Jay Phelps | @_jayphelps
fetchSomeData((error,	data)	=>	{	
		if	(!error)	{	
				dispatch({	type:	'HERES_THE_DATA',	data	});	
		}	
});
Callback Hell
Jay Phelps | @_jayphelps
fetchSomeData(id,	(error,	data)	=>	{	
		if	(!error)	{	
				dispatch({	type:	'HERES_THE_FIRST_CALL_DATA',	data	});	
				fetchSomeData(data.parentId,	(error,	data)	=>	{	
						if	(!error)	{	
								dispatch({	type:	'HERES_SOME_MORE',	data	});	
									
								fetchSomeData(data.parentId,	(error,	data)	=>	{	
										if	(!error)	{	
												dispatch({	type:	'OMG_MAKE_IT_STOP',	data	});	
										}	
								});	
						}	
				});	
		}	
});
Promises
Jay Phelps | @_jayphelps
fetchSomeData(id)	
		.then(data	=>	{	
				dispatch({	type:	'HERES_THE_FIRST_CALL_DATA',	data	});	
				return	fetchSomeData(data.parentId);	
		})	
		.then(data	=>	{	
				dispatch({	type:	'HERES_SOME_MORE',	data	});	
				return	fetchSomeData(data.parentId);	
		})	
		.then(data	=>	{	
				dispatch({	type:	'OKAY_IM_DONE',	data	});	
		});
Promises
Jay Phelps | @_jayphelps
• Guaranteed future
• Immutable
• Single value
• Caching
Promises
Jay Phelps | @_jayphelps
• Guaranteed future
• Immutable
• Single value
• Caching
Promises
Jay Phelps | @_jayphelps
• Guaranteed future
• Immutable
• Single value
• Caching
Jay Phelps | @_jayphelps
Promises cannot be cancelled
Jay Phelps | @_jayphelps
Why would you want to cancel?
Jay Phelps | @_jayphelps
• Changing routes/views
• Auto-complete
• User wants you to
Jay Phelps | @_jayphelps
• Changing routes/views
• Auto-complete
• User wants you to
Jay Phelps | @_jayphelps
Daredevil
Jay Phelps | @_jayphelps
Daredevil	
The	Get	Down	
Here’s	Daredevil!
Jay Phelps | @_jayphelps
Daredevil
Jay Phelps | @_jayphelps
Daredevil	
The	Get	Down
Jay Phelps | @_jayphelps
Cancelling is common and often overlooked
Promises
Jay Phelps | @_jayphelps
• Guaranteed future
• Immutable
• Single value
• Caching
Only AJAX is single value
Jay Phelps | @_jayphelps
• User interactions (mouse, keyboard, etc
• AJAX
• Animations
• WebSockets, Workers, etc
Jay Phelps | @_jayphelps
What do we use?
Jay Phelps | @_jayphelps
Observables
Observables
Jay Phelps | @_jayphelps
• Stream of zero, one, or more values
• Over any amount of time
• Cancellable
Jay Phelps | @_jayphelps
Streams are a set, with a dimension of time
Jay Phelps | @_jayphelps
Being standardized for ECMAScript aka JavaScript
RxJS
Jay Phelps | @_jayphelps
“lodash for async” - Ben Lesh
Crash Course
Jay Phelps | @_jayphelps
Creating Observables
Jay Phelps | @_jayphelps
• of('hello')	
• from([1,	2,	3,	4])		
• interval(1000)	
• ajax('http://example.com')	
• webSocket('ws://echo.websocket.com')	
• fromEvent(button,	‘click')	
• many more…
Subscribing
Jay Phelps | @_jayphelps
myObservable.subscribe(	
		value	=>	console.log('next',	value)	
);
Subscribing
Jay Phelps | @_jayphelps
myObservable.subscribe(	
		value	=>	console.log('next',	value),	
		err	=>	console.error('error',	err)	
);
Subscribing
Jay Phelps | @_jayphelps
myObservable.subscribe(	
		value	=>	console.log('next',	value),	
		err	=>	console.error('error',	err),	
		()	=>	console.info('complete!')	
);
Observables can be transformed
Jay Phelps | @_jayphelps
map, filter, reduce
Observables can be combined
Jay Phelps | @_jayphelps
concat, merge, zip
Observables represent time
Jay Phelps | @_jayphelps
debounce, throttle, buffer, combineLatest
Observables are lazy
Jay Phelps | @_jayphelps
retry, repeat
Jay Phelps | @_jayphelps
Observables can represent just about anything
Jay Phelps | @_jayphelps
Let’s combine RxJS and Redux!
Jay Phelps | @_jayphelps
Side effect management for redux, using Epics
What is an Epic?
Jay Phelps | @_jayphelps
A function that takes a stream of all actions dispatched
and returns a stream of new actions to dispatch
Jay Phelps | @_jayphelps
“actions in, actions out”
//	This	is	pseudo	code,	not	real	
function	pingPong(action,	store)	{	
		if	(action.type	===	'PING')	{	
				return	{	type:	'PONG'	};	
		}	
}
Jay Phelps | @_jayphelps
Sort of like this
function	pingPongEpic(action$,	store)	{	
		return	action$.ofType('PING')	
				.map(action	=>	({	type:	'PONG'	}));	
}
An Epic
Jay Phelps | @_jayphelps
const	pingPongEpic	=	(action$,	store)	=>	
		action$.ofType('PING')	
				.map(action	=>	({	type:	'PONG'	}));
An Epic
Jay Phelps | @_jayphelps
An Epic
Jay Phelps | @_jayphelps
const	pingPongEpic	=	(action$,	store)	=>	
		action$.ofType('PING')	
				.delay(1000)	//	<—	that's	it	
				.map(action	=>	({	type:	'PONG'	}));
Jay Phelps | @_jayphelps
const	isPinging	=	(state	=	false,	action)	=>	{	
		switch	(action.type)	{	
				case	'PING':	
						return	true;	
				case	'PONG':	
						return	false;	
				default:	
						return	state;	
		}	
};
const	pingPongEpic	=	(action$,	store)	=>	
		action$.ofType('PING')	
				.delay(1000)	
				.map(action	=>	({	type:	'PONG'	}));
Jay Phelps | @_jayphelps
Jay Phelps | @_jayphelps
Debounced increment / decrement button
Jay Phelps | @_jayphelps
const	counter	=	(state	=	0,	action)	=>	{	
		switch	(action.type)	{	
				case	'INCREMENT':	
						return	state	+	1;	
				case	'DECREMENT':	
						return	state	-	1;	
						
				default:	
						return	state;	
		}	
};
Jay Phelps | @_jayphelps
const	incrementEpic	=	(action$,	store)	=>	
		action$.ofType('INCREMENT_DEBOUNCED')	
				.debounceTime(1000)	
				.map(()	=>	({	type:	'INCREMENT'	}));	
const	decrementEpic	=	(action$,	store)	=>	
		action$.ofType('DECREMENT_DEBOUNCED')	
				.debounceTime(1000)	
				.map(()	=>	({	type:	'DECREMENT'	}));
Jay Phelps | @_jayphelps
const	incrementEpic	=	(action$,	store)	=>	
		action$.ofType('INCREMENT_DEBOUNCED')	
				.debounceTime(1000)	
				.map(()	=>	({	type:	'INCREMENT'	}));	
const	decrementEpic	=	(action$,	store)	=>	
		action$.ofType('DECREMENT_DEBOUNCED')	
				.debounceTime(1000)	
				.map(()	=>	({	type:	'DECREMENT'	}));
Jay Phelps | @_jayphelps
Those are contrived examples, obviously
Jay Phelps | @_jayphelps
Warning: non-trivial examples ahead,
don’t struggle to read them entirely
Jay Phelps | @_jayphelps
Auto-complete
Jay Phelps | @_jayphelps
		onKeyUp(e)	{	
				const	{	store	}	=	this.props;	
				const	{	value	}	=	e.target.value;	
				if	(this.queryId)	{	
						clearTimeout(this.queryId);	
				}	
				this.queryId	=	setTimeout(()	=>	{	
						if	(this.xhr)	{	
								this.xhr.abort();	
						}	
						const	xhr	=	this.xhr	=	new	XMLHttpRequest();	
						xhr.open('GET',	'https://api.github.com/search/users?q='	+	value);	
						xhr.onload	=	()	=>	{	
								if	(xhr.status	===	200)	{	
										store.dispatch({	
												type:	'QUERY_FULFILLED',	
												payload:	JSON.parse(xhr.response).items	
										});	
								}	else	{	
										store.dispatch({	
												type:	'QUERY_REJECTED',	
												error:	true,	
												payload:	{	
														message:	xhr.response,	
														status:	xhr.status	
												}	
										});	
								}	
						};	
						xhr.send();	
				},	500);	
		}
Plain JS
Jay Phelps | @_jayphelps
Epic
const	autoCompleteEpic	=	(action$,	store)	=>	
		action$.ofType('QUERY')	
				.debounceTime(500)	
				.switchMap(action	=>	
						ajax('https://api.github.com/search/users?q='	+	value)	
								.map(payload	=>	({	
										type:	'QUERY_FULFILLED',	
										payload	
								}))	
				);
Jay Phelps | @_jayphelps
Epic
const	autoCompleteEpic	=	(action$,	store)	=>	
		action$.ofType('QUERY')	
				.debounceTime(500)	
				.switchMap(action	=>	
						ajax('https://api.github.com/search/users?q='	+	value)	
								.map(payload	=>	({	
										type:	'QUERY_FULFILLED',	
										payload	
								}))	
								.catch(payload	=>	[{	
										type:	'QUERY_REJECTED',	
										error:	true,	
										payload	
								}])	
				);
Jay Phelps | @_jayphelps
Epic
const	autoCompleteEpic	=	(action$,	store)	=>	
		action$.ofType('QUERY')	
				.debounceTime(500)	
				.switchMap(action	=>	
						ajax('https://api.github.com/search/users?q='	+	value)	
								.map(payload	=>	({	
										type:	'QUERY_FULFILLED',	
										payload	
								}))	
								.takeUntil(action$.ofType('CANCEL_QUERY'))	
								.catch(payload	=>	[{	
										type:	'QUERY_REJECTED',	
										error:	true,	
										payload	
								}])	
				);
Jay Phelps | @_jayphelps
OK, show me really non-trivial examples
Jay Phelps | @_jayphelps
Bidirectional, multiplexed Web Sockets
Jay Phelps | @_jayphelps
class	Example	{	
		@autobind	
		checkChange(e)	{	
				const	{	value:	key,	checked	}	=	e.target;	
				this.subs	=	this.subs	||	[];	
				if	(checked)	{	
						const	handler	=	e	=>	{	
								const	data	=	JSON.parse(e.data);	
								if	(data.key	===	key)	{	
										this.updateValue(key,	data.value);	
								}	
						};	
						this.subs.push({	key,	handler	})	
						const	socket	=	this.getSocket(()	=>	{	
								this.setState({	
										socketOpen:	true	
								});	
								this.subs.forEach(({	key	})	=>	socket.send(JSON.stringify({	type:	'sub',	key})));	
						});	
						socket.addEventListener('message',	handler);	
				}	else	{	
						const	index	=	this.subs.findIndex(x	=>	x.key	===	key);	
						if	(index	!==	-1)	{	
								this.subs.splice(index,	1);	
						}	
						const	{	socket	}	=	this;	
						if	(socket	&&	socket.readyState	===	1)	{	
								socket.send(JSON.stringify({	type:	'unsub',	key	}));	
								this.setInactive(key)l	
								if	(this.subs.length	===	0)	{	
										socket.close();	
								}	
						}	
				}	
		}	
		componentWillUnMount()	{	
				if	(this.socket	&&	this.socket.readyState	===	1)	{	
						this.socket.close();	
				}	
		}
Plain JS
		getSocket(callback)	{	
				const	{	socket	}	=	this;	
				if	(socket	&&	socket.readyState	===	1)	{	
						setTimeot(callback);	
				}	else	{	
						if	(this.reconnectId)	{	
								clearTimeout(this.reconnectId);	
						}	
						socket	=	this.socket	=	new	WebSocket(‘ws://localhost:3000');	
						socket.onopen	=	()	=>	{	
								callback();	
						};	
						socket.onerror	=	()	=>	{	
								this.reconnectId	=	setTimeout(()	=>	this.getSocket(callback),	1000);	
								this.setState({	socketOpen:	false	});	
						};	
						socket.onclose	=	(e)	=>	{	
								if	(!e.wasClean)	{	
										this.reconnectId	=	setTimeout(()	=>	this.getSocket(callback),	1000);	
								}	
								this.setState({	socketOpen:	false	});	
						};	
				}	
					
				return	socket;	
		}	
}
Jay Phelps | @_jayphelps
Too much code
Jay Phelps | @_jayphelps
As an Epic
const	socket	=	WebSocketSubject.create('ws://stock/endpoint');	
const	stockTickerEpic	=	(action$,	store)	=>	
		action$.ofType('START_TICKER_STREAM')	
				.mergeMap(action	=>		
						socket.multiplex(	
								()	=>	({	sub:	action.ticker	}),	
								()	=>	({	unsub:	action.ticker	}),	
								msg	=>	msg.ticker	===	action.ticker	
						)	
						.retryWhen(	
								err	=>	window.navigator.onLine	?	
										Observable.timer(1000)	:	
										Observable.fromEvent(window,	'online')	
						)	
						.takeUntil(	
								action$.ofType('CLOSE_TICKER_STREAM')	
										.filter(closeAction	=>	closeAction.ticker	===	action.ticker)	
						)	
						.map(tick	=>	({	type:	'TICKER_TICK',	tick	}))	
				);
redux-observable
Jay Phelps | @_jayphelps
• Makes it easier to compose and control
complex async tasks, over any amount of time
• You don't need to manage your own Rx
subscriptions
• You can use redux tooling
But…
Jay Phelps | @_jayphelps
Jay Phelps | @_jayphelps
You should probably know redux and RxJS in advance
Jay Phelps | @_jayphelps
RxJS has a bit of a learning curve
Jay Phelps | @_jayphelps
“Reactive Programming”
Co-author
Jay Phelps | @_jayphelps
Ben Lesh
Senior UI Engineer |
@benlesh
Jay Phelps | @_jayphelps
https://redux-observable.js.org
Thanks!
@_jayphelps

More Related Content

What's hot

Angular & RXJS: examples and use cases
Angular & RXJS: examples and use casesAngular & RXJS: examples and use cases
Angular & RXJS: examples and use casesFabio Biondi
 
Authenticating Angular Apps with JWT
Authenticating Angular Apps with JWTAuthenticating Angular Apps with JWT
Authenticating Angular Apps with JWTJennifer Estrada
 
Introduction to Node.js
Introduction to Node.jsIntroduction to Node.js
Introduction to Node.jsVikash Singh
 
React + Redux Introduction
React + Redux IntroductionReact + Redux Introduction
React + Redux IntroductionNikolaus Graf
 
Getting Started with NgRx (Redux) Angular
Getting Started with NgRx (Redux) AngularGetting Started with NgRx (Redux) Angular
Getting Started with NgRx (Redux) AngularGustavo Costa
 
RxJS Evolved
RxJS EvolvedRxJS Evolved
RxJS Evolvedtrxcllnt
 
An introduction to React.js
An introduction to React.jsAn introduction to React.js
An introduction to React.jsEmanuele DelBono
 
Reactjs workshop
Reactjs workshop Reactjs workshop
Reactjs workshop Ahmed rebai
 
Redux Saga - Under the hood
Redux Saga - Under the hoodRedux Saga - Under the hood
Redux Saga - Under the hoodWaqqas Jabbar
 
React js - The Core Concepts
React js - The Core ConceptsReact js - The Core Concepts
React js - The Core ConceptsDivyang Bhambhani
 
Angular 4 The new Http Client Module
Angular 4 The new Http Client ModuleAngular 4 The new Http Client Module
Angular 4 The new Http Client Modulearjun singh
 

What's hot (20)

Angular & RXJS: examples and use cases
Angular & RXJS: examples and use casesAngular & RXJS: examples and use cases
Angular & RXJS: examples and use cases
 
Authenticating Angular Apps with JWT
Authenticating Angular Apps with JWTAuthenticating Angular Apps with JWT
Authenticating Angular Apps with JWT
 
Intro to React
Intro to ReactIntro to React
Intro to React
 
Introduction to Node.js
Introduction to Node.jsIntroduction to Node.js
Introduction to Node.js
 
React + Redux Introduction
React + Redux IntroductionReact + Redux Introduction
React + Redux Introduction
 
Practical Celery
Practical CeleryPractical Celery
Practical Celery
 
Getting Started with NgRx (Redux) Angular
Getting Started with NgRx (Redux) AngularGetting Started with NgRx (Redux) Angular
Getting Started with NgRx (Redux) Angular
 
RxJS Evolved
RxJS EvolvedRxJS Evolved
RxJS Evolved
 
An introduction to React.js
An introduction to React.jsAn introduction to React.js
An introduction to React.js
 
Reactjs workshop
Reactjs workshop Reactjs workshop
Reactjs workshop
 
Rxjs ppt
Rxjs pptRxjs ppt
Rxjs ppt
 
Thinking in react
Thinking in reactThinking in react
Thinking in react
 
Redux Saga - Under the hood
Redux Saga - Under the hoodRedux Saga - Under the hood
Redux Saga - Under the hood
 
React js - The Core Concepts
React js - The Core ConceptsReact js - The Core Concepts
React js - The Core Concepts
 
Intro to React
Intro to ReactIntro to React
Intro to React
 
Php variables
Php variablesPhp variables
Php variables
 
Rxjs ngvikings
Rxjs ngvikingsRxjs ngvikings
Rxjs ngvikings
 
An Introduction to Redux
An Introduction to ReduxAn Introduction to Redux
An Introduction to Redux
 
React and redux
React and reduxReact and redux
React and redux
 
Angular 4 The new Http Client Module
Angular 4 The new Http Client ModuleAngular 4 The new Http Client Module
Angular 4 The new Http Client Module
 

Similar to RxJS + Redux + React = Amazing

Real-time Insights, powered by Reactive Programming
Real-time Insights, powered by Reactive ProgrammingReal-time Insights, powered by Reactive Programming
Real-time Insights, powered by Reactive ProgrammingJay Phelps
 
React, Powered by WebAssembly
React, Powered by WebAssemblyReact, Powered by WebAssembly
React, Powered by WebAssemblyJay Phelps
 
The WebAssembly Revolution Has Begun
The WebAssembly Revolution Has BegunThe WebAssembly Revolution Has Begun
The WebAssembly Revolution Has BegunJay Phelps
 
Backpressure? Resistance is not futile. (Uphill Conf 2019)
Backpressure? Resistance is not futile. (Uphill Conf 2019)Backpressure? Resistance is not futile. (Uphill Conf 2019)
Backpressure? Resistance is not futile. (Uphill Conf 2019)Jay Phelps
 
WebAssembly Demystified
WebAssembly DemystifiedWebAssembly Demystified
WebAssembly DemystifiedJay Phelps
 
Asynchronous Interfaces
Asynchronous InterfacesAsynchronous Interfaces
Asynchronous Interfacesmaccman
 
WebAssembly. Neither Web Nor Assembly, All Revolutionary
WebAssembly. Neither Web Nor Assembly, All RevolutionaryWebAssembly. Neither Web Nor Assembly, All Revolutionary
WebAssembly. Neither Web Nor Assembly, All RevolutionaryC4Media
 
Intro to php
Intro to phpIntro to php
Intro to phpSp Singh
 
How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everythingnoelrap
 
Entry-level PHP for WordPress
Entry-level PHP for WordPressEntry-level PHP for WordPress
Entry-level PHP for WordPresssprclldr
 
Ditching JQuery
Ditching JQueryDitching JQuery
Ditching JQueryhowlowck
 
Effectively Testing Services - Burlington Ruby Conf
Effectively Testing Services - Burlington Ruby ConfEffectively Testing Services - Burlington Ruby Conf
Effectively Testing Services - Burlington Ruby Confneal_kemp
 
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
jQuery & 10,000 Global Functions: Working with Legacy JavaScriptjQuery & 10,000 Global Functions: Working with Legacy JavaScript
jQuery & 10,000 Global Functions: Working with Legacy JavaScriptGuy Royse
 
P H P Part I I, By Kian
P H P  Part  I I,  By  KianP H P  Part  I I,  By  Kian
P H P Part I I, By Kianphelios
 
Test driven APIs with Laravel
Test driven APIs with LaravelTest driven APIs with Laravel
Test driven APIs with LaravelMichael Peacock
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applicationselliando dias
 
DOM Scripting Toolkit - jQuery
DOM Scripting Toolkit - jQueryDOM Scripting Toolkit - jQuery
DOM Scripting Toolkit - jQueryRemy Sharp
 
You don’t know JS about SharePoint - Mastering javascript performance (Hugh W...
You don’t know JS about SharePoint - Mastering javascript performance (Hugh W...You don’t know JS about SharePoint - Mastering javascript performance (Hugh W...
You don’t know JS about SharePoint - Mastering javascript performance (Hugh W...Rencore
 

Similar to RxJS + Redux + React = Amazing (20)

Real-time Insights, powered by Reactive Programming
Real-time Insights, powered by Reactive ProgrammingReal-time Insights, powered by Reactive Programming
Real-time Insights, powered by Reactive Programming
 
React, Powered by WebAssembly
React, Powered by WebAssemblyReact, Powered by WebAssembly
React, Powered by WebAssembly
 
The WebAssembly Revolution Has Begun
The WebAssembly Revolution Has BegunThe WebAssembly Revolution Has Begun
The WebAssembly Revolution Has Begun
 
Backpressure? Resistance is not futile. (Uphill Conf 2019)
Backpressure? Resistance is not futile. (Uphill Conf 2019)Backpressure? Resistance is not futile. (Uphill Conf 2019)
Backpressure? Resistance is not futile. (Uphill Conf 2019)
 
WebAssembly Demystified
WebAssembly DemystifiedWebAssembly Demystified
WebAssembly Demystified
 
Asynchronous Interfaces
Asynchronous InterfacesAsynchronous Interfaces
Asynchronous Interfaces
 
WebAssembly. Neither Web Nor Assembly, All Revolutionary
WebAssembly. Neither Web Nor Assembly, All RevolutionaryWebAssembly. Neither Web Nor Assembly, All Revolutionary
WebAssembly. Neither Web Nor Assembly, All Revolutionary
 
Intro to php
Intro to phpIntro to php
Intro to php
 
How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everything
 
Entry-level PHP for WordPress
Entry-level PHP for WordPressEntry-level PHP for WordPress
Entry-level PHP for WordPress
 
Ditching JQuery
Ditching JQueryDitching JQuery
Ditching JQuery
 
Jsf Ajax
Jsf AjaxJsf Ajax
Jsf Ajax
 
Effectively Testing Services - Burlington Ruby Conf
Effectively Testing Services - Burlington Ruby ConfEffectively Testing Services - Burlington Ruby Conf
Effectively Testing Services - Burlington Ruby Conf
 
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
jQuery & 10,000 Global Functions: Working with Legacy JavaScriptjQuery & 10,000 Global Functions: Working with Legacy JavaScript
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
 
P H P Part I I, By Kian
P H P  Part  I I,  By  KianP H P  Part  I I,  By  Kian
P H P Part I I, By Kian
 
Test driven APIs with Laravel
Test driven APIs with LaravelTest driven APIs with Laravel
Test driven APIs with Laravel
 
PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applications
 
DOM Scripting Toolkit - jQuery
DOM Scripting Toolkit - jQueryDOM Scripting Toolkit - jQuery
DOM Scripting Toolkit - jQuery
 
JSF 2.0 Preview
JSF 2.0 PreviewJSF 2.0 Preview
JSF 2.0 Preview
 
You don’t know JS about SharePoint - Mastering javascript performance (Hugh W...
You don’t know JS about SharePoint - Mastering javascript performance (Hugh W...You don’t know JS about SharePoint - Mastering javascript performance (Hugh W...
You don’t know JS about SharePoint - Mastering javascript performance (Hugh W...
 

More from Jay Phelps

Backpressure? Resistance is not futile. RxJS Live 2019
Backpressure? Resistance is not futile. RxJS Live 2019Backpressure? Resistance is not futile. RxJS Live 2019
Backpressure? Resistance is not futile. RxJS Live 2019Jay Phelps
 
Why I Love JSX!
Why I Love JSX!Why I Love JSX!
Why I Love JSX!Jay Phelps
 
ES2015 and Beyond
ES2015 and BeyondES2015 and Beyond
ES2015 and BeyondJay Phelps
 
Intro to Ember CLI
Intro to Ember CLIIntro to Ember CLI
Intro to Ember CLIJay Phelps
 
Ember Overview in 5 Minutes
Ember Overview in 5 MinutesEmber Overview in 5 Minutes
Ember Overview in 5 MinutesJay Phelps
 
Profit From Your Media Library Using Multi-Platform Distribution
Profit From Your Media Library Using Multi-Platform DistributionProfit From Your Media Library Using Multi-Platform Distribution
Profit From Your Media Library Using Multi-Platform DistributionJay Phelps
 
Intro to Ember.js
Intro to Ember.jsIntro to Ember.js
Intro to Ember.jsJay Phelps
 

More from Jay Phelps (7)

Backpressure? Resistance is not futile. RxJS Live 2019
Backpressure? Resistance is not futile. RxJS Live 2019Backpressure? Resistance is not futile. RxJS Live 2019
Backpressure? Resistance is not futile. RxJS Live 2019
 
Why I Love JSX!
Why I Love JSX!Why I Love JSX!
Why I Love JSX!
 
ES2015 and Beyond
ES2015 and BeyondES2015 and Beyond
ES2015 and Beyond
 
Intro to Ember CLI
Intro to Ember CLIIntro to Ember CLI
Intro to Ember CLI
 
Ember Overview in 5 Minutes
Ember Overview in 5 MinutesEmber Overview in 5 Minutes
Ember Overview in 5 Minutes
 
Profit From Your Media Library Using Multi-Platform Distribution
Profit From Your Media Library Using Multi-Platform DistributionProfit From Your Media Library Using Multi-Platform Distribution
Profit From Your Media Library Using Multi-Platform Distribution
 
Intro to Ember.js
Intro to Ember.jsIntro to Ember.js
Intro to Ember.js
 

Recently uploaded

%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in sowetomasabamasaba
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfonteinmasabamasaba
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfonteinmasabamasaba
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyviewmasabamasaba
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionOnePlan Solutions
 
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
Harnessing ChatGPT - Elevating Productivity in Today's Agile Environment
Harnessing ChatGPT  - Elevating Productivity in Today's Agile EnvironmentHarnessing ChatGPT  - Elevating Productivity in Today's Agile Environment
Harnessing ChatGPT - Elevating Productivity in Today's Agile EnvironmentVictorSzoltysek
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...Shane Coughlan
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...masabamasaba
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrandmasabamasaba
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...masabamasaba
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesVictorSzoltysek
 

Recently uploaded (20)

%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
Harnessing ChatGPT - Elevating Productivity in Today's Agile Environment
Harnessing ChatGPT  - Elevating Productivity in Today's Agile EnvironmentHarnessing ChatGPT  - Elevating Productivity in Today's Agile Environment
Harnessing ChatGPT - Elevating Productivity in Today's Agile Environment
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 

RxJS + Redux + React = Amazing

  • 1. RxJS + Redux + React = Amazing Jay Phelps | @_jayphelps Side Effect Management with RxJS
  • 2. Jay Phelps | @_jayphelps Managing state stuff is hard
  • 3. Jay Phelps | @_jayphelps Redux makes it simple (not necessarily easy)
  • 4. Jay Phelps | @_jayphelps Managing async stuff is harder
  • 5. Jay Phelps | @_jayphelps Some async is complex regardless of the abstraction
  • 6. Jay Phelps | @_jayphelps RxJS makes it manageable
  • 7. Jay Phelps Senior Software Engineer | @_jayphelps
  • 8. What is redux? Jay Phelps | @_jayphelps
  • 9. Crash Course Jay Phelps | @_jayphelps
  • 10. What is redux? Jay Phelps | @_jayphelps Provides predicable state management using actions and reducers
  • 11. What's an "action"? Jay Phelps | @_jayphelps Describes something has (or should) happen, but they don't specify how it should be done
  • 12. Jay Phelps | @_jayphelps { type: 'CREATE_TODO', payload: 'Build my first Redux app' }
  • 13. What's an "reducer"? Jay Phelps | @_jayphelps A pure function that takes the previous state and an action and returns the new state
  • 14. What's an "reducer"? Jay Phelps | @_jayphelps Sometimes it returns the previous state (state, action) => state
  • 15. What's an "reducer"? Jay Phelps | @_jayphelps Sometimes it computes new state (state, action) => state + action.payload
  • 16. Jay Phelps | @_jayphelps const counter = (state = 0, action) => { switch (action.type) { case 'INCREMENT': return state + 1; case 'DECREMENT': return state - 1; default: return state; } };
  • 17. Jay Phelps | @_jayphelps Reducers handle state transitions, but they must be done synchronously.
  • 18. Jay Phelps | @_jayphelps const counter = (state = 0, action) => { switch (action.type) { case 'INCREMENT': return state + 1; case 'DECREMENT': return state - 1; default: return state; } };
  • 19. Jay Phelps | @_jayphelps What are async stuff do we commonly do?
  • 20. Async Jay Phelps | @_jayphelps • User interactions (mouse, keyboard, etc) • AJAX • Timers/Animations • Web Sockets • Work Workers, etc
  • 21. Jay Phelps | @_jayphelps Some can be handled synchronously
  • 22. Jay Phelps | @_jayphelps <button onClick={() => dispatch({ type: 'INCREMENT' })}> Increment </button>
  • 23. Jay Phelps | @_jayphelps const counter = (state = 0, action) => { switch (action.type) { case 'INCREMENT': return state + 1; case 'DECREMENT': return state - 1; default: return state; } };
  • 24. Jay Phelps | @_jayphelps Sometimes you need more control
  • 25. Jay Phelps | @_jayphelps • AJAX cancellation/composing • Debounce/throttle/buffer/etc • Drag and Drop • Web Sockets, Work Workers, etc
  • 26. Jay Phelps | @_jayphelps Use middleware to manage async / side effects
  • 27. Jay Phelps | @_jayphelps Most of them use callbacks or Promises
  • 28. Callbacks Jay Phelps | @_jayphelps The most primitive way to handle async in JavaScript
  • 29. Callbacks Jay Phelps | @_jayphelps fetchSomeData((error, data) => { if (!error) { dispatch({ type: 'HERES_THE_DATA', data }); } });
  • 30. Callback Hell Jay Phelps | @_jayphelps fetchSomeData(id, (error, data) => { if (!error) { dispatch({ type: 'HERES_THE_FIRST_CALL_DATA', data }); fetchSomeData(data.parentId, (error, data) => { if (!error) { dispatch({ type: 'HERES_SOME_MORE', data }); fetchSomeData(data.parentId, (error, data) => { if (!error) { dispatch({ type: 'OMG_MAKE_IT_STOP', data }); } }); } }); } });
  • 31. Promises Jay Phelps | @_jayphelps fetchSomeData(id) .then(data => { dispatch({ type: 'HERES_THE_FIRST_CALL_DATA', data }); return fetchSomeData(data.parentId); }) .then(data => { dispatch({ type: 'HERES_SOME_MORE', data }); return fetchSomeData(data.parentId); }) .then(data => { dispatch({ type: 'OKAY_IM_DONE', data }); });
  • 32. Promises Jay Phelps | @_jayphelps • Guaranteed future • Immutable • Single value • Caching
  • 33. Promises Jay Phelps | @_jayphelps • Guaranteed future • Immutable • Single value • Caching
  • 34. Promises Jay Phelps | @_jayphelps • Guaranteed future • Immutable • Single value • Caching
  • 35. Jay Phelps | @_jayphelps Promises cannot be cancelled
  • 36. Jay Phelps | @_jayphelps Why would you want to cancel?
  • 37. Jay Phelps | @_jayphelps • Changing routes/views • Auto-complete • User wants you to
  • 38. Jay Phelps | @_jayphelps • Changing routes/views • Auto-complete • User wants you to
  • 39. Jay Phelps | @_jayphelps Daredevil
  • 40. Jay Phelps | @_jayphelps Daredevil The Get Down Here’s Daredevil!
  • 41. Jay Phelps | @_jayphelps Daredevil
  • 42. Jay Phelps | @_jayphelps Daredevil The Get Down
  • 43. Jay Phelps | @_jayphelps Cancelling is common and often overlooked
  • 44. Promises Jay Phelps | @_jayphelps • Guaranteed future • Immutable • Single value • Caching
  • 45. Only AJAX is single value Jay Phelps | @_jayphelps • User interactions (mouse, keyboard, etc • AJAX • Animations • WebSockets, Workers, etc
  • 46. Jay Phelps | @_jayphelps What do we use?
  • 47. Jay Phelps | @_jayphelps Observables
  • 48. Observables Jay Phelps | @_jayphelps • Stream of zero, one, or more values • Over any amount of time • Cancellable
  • 49. Jay Phelps | @_jayphelps Streams are a set, with a dimension of time
  • 50. Jay Phelps | @_jayphelps Being standardized for ECMAScript aka JavaScript
  • 51. RxJS Jay Phelps | @_jayphelps “lodash for async” - Ben Lesh
  • 52. Crash Course Jay Phelps | @_jayphelps
  • 53. Creating Observables Jay Phelps | @_jayphelps • of('hello') • from([1, 2, 3, 4]) • interval(1000) • ajax('http://example.com') • webSocket('ws://echo.websocket.com') • fromEvent(button, ‘click') • many more…
  • 54. Subscribing Jay Phelps | @_jayphelps myObservable.subscribe( value => console.log('next', value) );
  • 55. Subscribing Jay Phelps | @_jayphelps myObservable.subscribe( value => console.log('next', value), err => console.error('error', err) );
  • 56. Subscribing Jay Phelps | @_jayphelps myObservable.subscribe( value => console.log('next', value), err => console.error('error', err), () => console.info('complete!') );
  • 57. Observables can be transformed Jay Phelps | @_jayphelps map, filter, reduce
  • 58. Observables can be combined Jay Phelps | @_jayphelps concat, merge, zip
  • 59. Observables represent time Jay Phelps | @_jayphelps debounce, throttle, buffer, combineLatest
  • 60. Observables are lazy Jay Phelps | @_jayphelps retry, repeat
  • 61. Jay Phelps | @_jayphelps Observables can represent just about anything
  • 62. Jay Phelps | @_jayphelps Let’s combine RxJS and Redux!
  • 63. Jay Phelps | @_jayphelps
  • 64.
  • 65. Side effect management for redux, using Epics
  • 66. What is an Epic? Jay Phelps | @_jayphelps A function that takes a stream of all actions dispatched and returns a stream of new actions to dispatch
  • 67. Jay Phelps | @_jayphelps “actions in, actions out”
  • 71. An Epic Jay Phelps | @_jayphelps const pingPongEpic = (action$, store) => action$.ofType('PING') .delay(1000) // <— that's it .map(action => ({ type: 'PONG' }));
  • 72. Jay Phelps | @_jayphelps const isPinging = (state = false, action) => { switch (action.type) { case 'PING': return true; case 'PONG': return false; default: return state; } };
  • 74. Jay Phelps | @_jayphelps Debounced increment / decrement button
  • 75. Jay Phelps | @_jayphelps const counter = (state = 0, action) => { switch (action.type) { case 'INCREMENT': return state + 1; case 'DECREMENT': return state - 1; default: return state; } };
  • 76. Jay Phelps | @_jayphelps const incrementEpic = (action$, store) => action$.ofType('INCREMENT_DEBOUNCED') .debounceTime(1000) .map(() => ({ type: 'INCREMENT' })); const decrementEpic = (action$, store) => action$.ofType('DECREMENT_DEBOUNCED') .debounceTime(1000) .map(() => ({ type: 'DECREMENT' }));
  • 77. Jay Phelps | @_jayphelps const incrementEpic = (action$, store) => action$.ofType('INCREMENT_DEBOUNCED') .debounceTime(1000) .map(() => ({ type: 'INCREMENT' })); const decrementEpic = (action$, store) => action$.ofType('DECREMENT_DEBOUNCED') .debounceTime(1000) .map(() => ({ type: 'DECREMENT' }));
  • 78. Jay Phelps | @_jayphelps Those are contrived examples, obviously
  • 79. Jay Phelps | @_jayphelps Warning: non-trivial examples ahead, don’t struggle to read them entirely
  • 80. Jay Phelps | @_jayphelps Auto-complete
  • 81. Jay Phelps | @_jayphelps onKeyUp(e) { const { store } = this.props; const { value } = e.target.value; if (this.queryId) { clearTimeout(this.queryId); } this.queryId = setTimeout(() => { if (this.xhr) { this.xhr.abort(); } const xhr = this.xhr = new XMLHttpRequest(); xhr.open('GET', 'https://api.github.com/search/users?q=' + value); xhr.onload = () => { if (xhr.status === 200) { store.dispatch({ type: 'QUERY_FULFILLED', payload: JSON.parse(xhr.response).items }); } else { store.dispatch({ type: 'QUERY_REJECTED', error: true, payload: { message: xhr.response, status: xhr.status } }); } }; xhr.send(); }, 500); } Plain JS
  • 82. Jay Phelps | @_jayphelps Epic const autoCompleteEpic = (action$, store) => action$.ofType('QUERY') .debounceTime(500) .switchMap(action => ajax('https://api.github.com/search/users?q=' + value) .map(payload => ({ type: 'QUERY_FULFILLED', payload })) );
  • 83. Jay Phelps | @_jayphelps Epic const autoCompleteEpic = (action$, store) => action$.ofType('QUERY') .debounceTime(500) .switchMap(action => ajax('https://api.github.com/search/users?q=' + value) .map(payload => ({ type: 'QUERY_FULFILLED', payload })) .catch(payload => [{ type: 'QUERY_REJECTED', error: true, payload }]) );
  • 84. Jay Phelps | @_jayphelps Epic const autoCompleteEpic = (action$, store) => action$.ofType('QUERY') .debounceTime(500) .switchMap(action => ajax('https://api.github.com/search/users?q=' + value) .map(payload => ({ type: 'QUERY_FULFILLED', payload })) .takeUntil(action$.ofType('CANCEL_QUERY')) .catch(payload => [{ type: 'QUERY_REJECTED', error: true, payload }]) );
  • 85. Jay Phelps | @_jayphelps OK, show me really non-trivial examples
  • 86. Jay Phelps | @_jayphelps Bidirectional, multiplexed Web Sockets
  • 87. Jay Phelps | @_jayphelps class Example { @autobind checkChange(e) { const { value: key, checked } = e.target; this.subs = this.subs || []; if (checked) { const handler = e => { const data = JSON.parse(e.data); if (data.key === key) { this.updateValue(key, data.value); } }; this.subs.push({ key, handler }) const socket = this.getSocket(() => { this.setState({ socketOpen: true }); this.subs.forEach(({ key }) => socket.send(JSON.stringify({ type: 'sub', key}))); }); socket.addEventListener('message', handler); } else { const index = this.subs.findIndex(x => x.key === key); if (index !== -1) { this.subs.splice(index, 1); } const { socket } = this; if (socket && socket.readyState === 1) { socket.send(JSON.stringify({ type: 'unsub', key })); this.setInactive(key)l if (this.subs.length === 0) { socket.close(); } } } } componentWillUnMount() { if (this.socket && this.socket.readyState === 1) { this.socket.close(); } } Plain JS getSocket(callback) { const { socket } = this; if (socket && socket.readyState === 1) { setTimeot(callback); } else { if (this.reconnectId) { clearTimeout(this.reconnectId); } socket = this.socket = new WebSocket(‘ws://localhost:3000'); socket.onopen = () => { callback(); }; socket.onerror = () => { this.reconnectId = setTimeout(() => this.getSocket(callback), 1000); this.setState({ socketOpen: false }); }; socket.onclose = (e) => { if (!e.wasClean) { this.reconnectId = setTimeout(() => this.getSocket(callback), 1000); } this.setState({ socketOpen: false }); }; } return socket; } }
  • 88. Jay Phelps | @_jayphelps Too much code
  • 89. Jay Phelps | @_jayphelps As an Epic const socket = WebSocketSubject.create('ws://stock/endpoint'); const stockTickerEpic = (action$, store) => action$.ofType('START_TICKER_STREAM') .mergeMap(action => socket.multiplex( () => ({ sub: action.ticker }), () => ({ unsub: action.ticker }), msg => msg.ticker === action.ticker ) .retryWhen( err => window.navigator.onLine ? Observable.timer(1000) : Observable.fromEvent(window, 'online') ) .takeUntil( action$.ofType('CLOSE_TICKER_STREAM') .filter(closeAction => closeAction.ticker === action.ticker) ) .map(tick => ({ type: 'TICKER_TICK', tick })) );
  • 90. redux-observable Jay Phelps | @_jayphelps • Makes it easier to compose and control complex async tasks, over any amount of time • You don't need to manage your own Rx subscriptions • You can use redux tooling
  • 91. But… Jay Phelps | @_jayphelps
  • 92. Jay Phelps | @_jayphelps You should probably know redux and RxJS in advance
  • 93. Jay Phelps | @_jayphelps RxJS has a bit of a learning curve
  • 94. Jay Phelps | @_jayphelps “Reactive Programming”
  • 95. Co-author Jay Phelps | @_jayphelps Ben Lesh Senior UI Engineer | @benlesh
  • 96. Jay Phelps | @_jayphelps https://redux-observable.js.org
  • 97.