SlideShare ist ein Scribd-Unternehmen logo
1 von 98
Downloaden Sie, um offline zu lesen
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

Weitere ähnliche Inhalte

Was ist angesagt?

Introduction to React
Introduction to ReactIntroduction to React
Introduction to ReactRob Quick
 
Hibernate presentation
Hibernate presentationHibernate presentation
Hibernate presentationManav Prasad
 
[Final] ReactJS presentation
[Final] ReactJS presentation[Final] ReactJS presentation
[Final] ReactJS presentation洪 鹏发
 
Introduction to ReactJS
Introduction to ReactJSIntroduction to ReactJS
Introduction to ReactJSHoang Long
 
Understanding React hooks | Walkingtree Technologies
Understanding React hooks | Walkingtree TechnologiesUnderstanding React hooks | Walkingtree Technologies
Understanding React hooks | Walkingtree TechnologiesWalking Tree Technologies
 
React js - The Core Concepts
React js - The Core ConceptsReact js - The Core Concepts
React js - The Core ConceptsDivyang Bhambhani
 
Introduction to Drools
Introduction to DroolsIntroduction to Drools
Introduction to Droolsgiurca
 
An introduction to React.js
An introduction to React.jsAn introduction to React.js
An introduction to React.jsEmanuele DelBono
 
React JS & Functional Programming Principles
React JS & Functional Programming PrinciplesReact JS & Functional Programming Principles
React JS & Functional Programming PrinciplesAndrii Lundiak
 
Introduction to react-query. A Redux alternative? (Nikos Kleidis, Front End D...
Introduction to react-query. A Redux alternative? (Nikos Kleidis, Front End D...Introduction to react-query. A Redux alternative? (Nikos Kleidis, Front End D...
Introduction to react-query. A Redux alternative? (Nikos Kleidis, Front End D...GreeceJS
 
React JS - A quick introduction tutorial
React JS - A quick introduction tutorialReact JS - A quick introduction tutorial
React JS - A quick introduction tutorialMohammed Fazuluddin
 

Was ist angesagt? (20)

Introduction to React
Introduction to ReactIntroduction to React
Introduction to React
 
Its time to React.js
Its time to React.jsIts time to React.js
Its time to React.js
 
Hibernate presentation
Hibernate presentationHibernate presentation
Hibernate presentation
 
React JS part 1
React JS part 1React JS part 1
React JS part 1
 
[Final] ReactJS presentation
[Final] ReactJS presentation[Final] ReactJS presentation
[Final] ReactJS presentation
 
React JS - Introduction
React JS - IntroductionReact JS - Introduction
React JS - Introduction
 
Reactjs
Reactjs Reactjs
Reactjs
 
Introduction to ReactJS
Introduction to ReactJSIntroduction to ReactJS
Introduction to ReactJS
 
Understanding React hooks | Walkingtree Technologies
Understanding React hooks | Walkingtree TechnologiesUnderstanding React hooks | Walkingtree Technologies
Understanding React hooks | Walkingtree Technologies
 
react redux.pdf
react redux.pdfreact redux.pdf
react redux.pdf
 
Reactjs
ReactjsReactjs
Reactjs
 
React js - The Core Concepts
React js - The Core ConceptsReact js - The Core Concepts
React js - The Core Concepts
 
Introduction to Drools
Introduction to DroolsIntroduction to Drools
Introduction to Drools
 
An introduction to React.js
An introduction to React.jsAn introduction to React.js
An introduction to React.js
 
React hooks
React hooksReact hooks
React hooks
 
React JS & Functional Programming Principles
React JS & Functional Programming PrinciplesReact JS & Functional Programming Principles
React JS & Functional Programming Principles
 
React workshop
React workshopReact workshop
React workshop
 
Introduction to react-query. A Redux alternative? (Nikos Kleidis, Front End D...
Introduction to react-query. A Redux alternative? (Nikos Kleidis, Front End D...Introduction to react-query. A Redux alternative? (Nikos Kleidis, Front End D...
Introduction to react-query. A Redux alternative? (Nikos Kleidis, Front End D...
 
React Hooks
React HooksReact Hooks
React Hooks
 
React JS - A quick introduction tutorial
React JS - A quick introduction tutorialReact JS - A quick introduction tutorial
React JS - A quick introduction tutorial
 

Andere mochten auch

React + Redux. Best practices
React + Redux.  Best practicesReact + Redux.  Best practices
React + Redux. Best practicesClickky
 
React + Redux Introduction
React + Redux IntroductionReact + Redux Introduction
React + Redux IntroductionNikolaus Graf
 
LastaFluteに移行したFessとElasticsearch+ESFluteによるDBFlute環境
LastaFluteに移行したFessとElasticsearch+ESFluteによるDBFlute環境LastaFluteに移行したFessとElasticsearch+ESFluteによるDBFlute環境
LastaFluteに移行したFessとElasticsearch+ESFluteによるDBFlute環境Shinsuke Sugaya
 

Andere mochten auch (6)

React and redux
React and reduxReact and redux
React and redux
 
React + Redux. Best practices
React + Redux.  Best practicesReact + Redux.  Best practices
React + Redux. Best practices
 
Introduction to Redux
Introduction to ReduxIntroduction to Redux
Introduction to Redux
 
Let's Redux!
Let's Redux!Let's Redux!
Let's Redux!
 
React + Redux Introduction
React + Redux IntroductionReact + Redux Introduction
React + Redux Introduction
 
LastaFluteに移行したFessとElasticsearch+ESFluteによるDBFlute環境
LastaFluteに移行したFessとElasticsearch+ESFluteによるDBFlute環境LastaFluteに移行したFessとElasticsearch+ESFluteによるDBFlute環境
LastaFluteに移行したFessとElasticsearch+ESFluteによるDBFlute環境
 

Ähnlich wie 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
 

Ähnlich wie 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...
 

Mehr von 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
 

Mehr von 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
 

Kürzlich hochgeladen

Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendArshad QA
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️anilsa9823
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...OnePlan Solutions
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfkalichargn70th171
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number SystemsJheuzeDellosa
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 

Kürzlich hochgeladen (20)

Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and Backend
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
Exploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the ProcessExploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the Process
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number Systems
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 

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.