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

Apache Hadoop YARN: best practices
Apache Hadoop YARN: best practicesApache Hadoop YARN: best practices
Apache Hadoop YARN: best practicesDataWorks Summit
 
스프링 부트와 로깅
스프링 부트와 로깅스프링 부트와 로깅
스프링 부트와 로깅Keesun Baik
 
Apache Spark Fundamentals
Apache Spark FundamentalsApache Spark Fundamentals
Apache Spark FundamentalsZahra Eskandari
 
Manage react state with MobX
Manage react state with MobXManage react state with MobX
Manage react state with MobXAsif Nawaz
 
Working with JSON Data in PostgreSQL vs. MongoDB
Working with JSON Data in PostgreSQL vs. MongoDBWorking with JSON Data in PostgreSQL vs. MongoDB
Working with JSON Data in PostgreSQL vs. MongoDBScaleGrid.io
 
Apache Karaf - Building OSGi applications on Apache Karaf - T Frank & A Grzesik
Apache Karaf - Building OSGi applications on Apache Karaf - T Frank & A GrzesikApache Karaf - Building OSGi applications on Apache Karaf - T Frank & A Grzesik
Apache Karaf - Building OSGi applications on Apache Karaf - T Frank & A Grzesikmfrancis
 
Oak, the architecture of Apache Jackrabbit 3
Oak, the architecture of Apache Jackrabbit 3Oak, the architecture of Apache Jackrabbit 3
Oak, the architecture of Apache Jackrabbit 3Jukka Zitting
 
Javascript Module Patterns
Javascript Module PatternsJavascript Module Patterns
Javascript Module PatternsNicholas Jansma
 
T-Mobile.pl: Powering Telco AIOps with Elastic Machine Learning
T-Mobile.pl: Powering Telco AIOps with Elastic Machine LearningT-Mobile.pl: Powering Telco AIOps with Elastic Machine Learning
T-Mobile.pl: Powering Telco AIOps with Elastic Machine LearningElasticsearch
 
Introduction to MongoDB
Introduction to MongoDBIntroduction to MongoDB
Introduction to MongoDBNodeXperts
 
Getting started with Redux js
Getting started with Redux jsGetting started with Redux js
Getting started with Redux jsCitrix
 
20090713 Hbase Schema Design Case Studies
20090713 Hbase Schema Design Case Studies20090713 Hbase Schema Design Case Studies
20090713 Hbase Schema Design Case StudiesEvan Liu
 
Building RESTful applications using Spring MVC
Building RESTful applications using Spring MVCBuilding RESTful applications using Spring MVC
Building RESTful applications using Spring MVCIndicThreads
 
Content Storage With Apache Jackrabbit
Content Storage With Apache JackrabbitContent Storage With Apache Jackrabbit
Content Storage With Apache JackrabbitJukka Zitting
 

What's hot (20)

Apache Hadoop YARN: best practices
Apache Hadoop YARN: best practicesApache Hadoop YARN: best practices
Apache Hadoop YARN: best practices
 
스프링 부트와 로깅
스프링 부트와 로깅스프링 부트와 로깅
스프링 부트와 로깅
 
Apache Spark Fundamentals
Apache Spark FundamentalsApache Spark Fundamentals
Apache Spark Fundamentals
 
Manage react state with MobX
Manage react state with MobXManage react state with MobX
Manage react state with MobX
 
Working with JSON Data in PostgreSQL vs. MongoDB
Working with JSON Data in PostgreSQL vs. MongoDBWorking with JSON Data in PostgreSQL vs. MongoDB
Working with JSON Data in PostgreSQL vs. MongoDB
 
Apache Karaf - Building OSGi applications on Apache Karaf - T Frank & A Grzesik
Apache Karaf - Building OSGi applications on Apache Karaf - T Frank & A GrzesikApache Karaf - Building OSGi applications on Apache Karaf - T Frank & A Grzesik
Apache Karaf - Building OSGi applications on Apache Karaf - T Frank & A Grzesik
 
Oak, the architecture of Apache Jackrabbit 3
Oak, the architecture of Apache Jackrabbit 3Oak, the architecture of Apache Jackrabbit 3
Oak, the architecture of Apache Jackrabbit 3
 
Javascript Module Patterns
Javascript Module PatternsJavascript Module Patterns
Javascript Module Patterns
 
T-Mobile.pl: Powering Telco AIOps with Elastic Machine Learning
T-Mobile.pl: Powering Telco AIOps with Elastic Machine LearningT-Mobile.pl: Powering Telco AIOps with Elastic Machine Learning
T-Mobile.pl: Powering Telco AIOps with Elastic Machine Learning
 
Introduction to MongoDB
Introduction to MongoDBIntroduction to MongoDB
Introduction to MongoDB
 
Introduction to GraphQL
Introduction to GraphQLIntroduction to GraphQL
Introduction to GraphQL
 
Getting started with Redux js
Getting started with Redux jsGetting started with Redux js
Getting started with Redux js
 
20090713 Hbase Schema Design Case Studies
20090713 Hbase Schema Design Case Studies20090713 Hbase Schema Design Case Studies
20090713 Hbase Schema Design Case Studies
 
React and redux
React and reduxReact and redux
React and redux
 
A Web é uma API
A Web é uma APIA Web é uma API
A Web é uma API
 
Java 17
Java 17Java 17
Java 17
 
Spring boot
Spring bootSpring boot
Spring boot
 
Java 8 lambda
Java 8 lambdaJava 8 lambda
Java 8 lambda
 
Building RESTful applications using Spring MVC
Building RESTful applications using Spring MVCBuilding RESTful applications using Spring MVC
Building RESTful applications using Spring MVC
 
Content Storage With Apache Jackrabbit
Content Storage With Apache JackrabbitContent Storage With Apache Jackrabbit
Content Storage With Apache Jackrabbit
 

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

Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...OnePlan Solutions
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfStefano Stabellini
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Matt Ray
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtimeandrehoraa
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesŁukasz Chruściel
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfFerryKemperman
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfMarharyta Nedzelska
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanyChristoph Pohl
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024StefanoLambiase
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationBradBedford3
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Velvetech LLC
 

Recently uploaded (20)

Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdf
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtime
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New Features
 
2.pdf Ejercicios de programación competitiva
2.pdf Ejercicios de programación competitiva2.pdf Ejercicios de programación competitiva
2.pdf Ejercicios de programación competitiva
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdf
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdf
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion Application
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...
 

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.