42

[Codecamp 2016] Going functional with flyd and react

Embed Size (px)

Citation preview

GOING

FUNCTIONALwith

Flyd and React

Cazaciuc Gabriel Team lead@Softvision

About me

Complex vs Simple“...there is one quality that

cannot be purchased... —

and that is reliability. The

price of reliability is the

pursuit of the utmost

simplicity”

Tony Hoare

Control flow Unexpressive code State mutations Synchronizing sources of truth Async flows

Complexity

STATE Biggest source of complexity

Actions

Typical web application

State DOM

Simple problem.Heavy solutions.

MVC MVPMVVM

PubSub

no worries ...

we’ve got Flux

What the Flux is this ?

Flux - No silver bullet

Lots of boilerplate(vanilla Flux)

Just as easy to create tangled code

Store updates inter-dependencies

Async flows are as hard Ajax

Dispatchers

emit changes

waitForStore

cascading actions

Action creators

Handling STATE with style

➢ Views as pure representations of state

➢ Centralized state management

➢ Predictable state updates

➢ Simple control flow

➢ Simplified asynchronous state control

➢ More meaningful code

App timeBuilding a search service

Down to essentials

The Viewexport const SearchBox = () => { const onSearch = (e) => { searchPhotos({tags: e.target.value}); }; return ( <TextField hintText="Search photo tags..." onChange={onSearch} /> );}

The STATEconst INITIAL_APP_STATE = Object.freeze({ photos: [], isLoadingPhotos: false, searchTerm: ''});

Invoking actionsexport const SearchBox = () => { const onSearch = (e) => { searchPhotos({tags: e.target.value}); }; return ( <TextField hintText="Search photo tags..." onChange={onSearch} /> );}

searchPhotos({tags: e.target.value});

How do you dispatch that ?

Flyd streams

const searchPhotos = flyd.stream()

We’ve got a function

searchPhotos()

searchPhotos(‘flowers’)

Simplest Flux. Ever

export const searchPhotos = flyd.stream()

the action

const searchReducer = (state, payload) =>

Object.assign( {}, state, {term : payload} )

the reducer(action to next state mapper)

export const AppState = flyd.scan(searchReducer ,

INITIAL_STATE ,

searchPhotos )

another stream

flyd.on((state) => {

ReactDOM.render(

<App state={state} />,

document.querySelector('#app'));

},

AppState)

the view

Flyd stream operators

Map

const resultStream = flyd.map( x => 10*x , numbersStream )

Filter

import filter from ‘flyd-filter’const greaterThan10 = filter( x => x > 10 , numStr )

Scan

const sumStr = flyd.scan((x,y)=>x+y, numbersStream, 0)

Merge

const mergedStr = flyd.merge(divisibleByTenStr, oneStream)

And dozens of other stream operators...

https://github.com/paldepind/flyd#modules

Scaling up the Flux pattern

PhotoActions.js export const searchPhotos = flyd.stream()export const photosLoaded = ...

PhotoReducers.jsexport const searchPhotosReducer = (currentState, action) => { return Object.assign({}, currentState, { currentSearchTerm: action.tags });};

export const photosLoadedReducer = (currentState, action) => ….

AppState.js

const AppState$ = scanMerge( [ [searchPhotos, searchPhotosReducer], [photosLoaded, photosLoadedReducer] ... ], INITIAL_APP_STATE);

Async actions

const url = ( tags ) =>`${API_ENDPOINT}?&tags=${tags}`const req = (url) => fetch(url);const toJSON = (response) => response.json();

const responses = flyd.map( (action) => window.fetch(url(action.tags)), searchPhotos );

export const photosLoaded = flyd.map(toJSON, responses);

const workerResponses = flyd.stream();worker.onmessage = workerResponses;

const workerTasks = flyd.map( worker.postMessage, responses);const photosLoaded = flyd.map((e)=>e.data, workerResponses);

Or maybe doing some heavy stuff ?

What we achieved ?Simpler Flux

Actions - Flyd streams Reducers - pure functions AppState - one application state

Simpler async flowsMore meaningful, higher level, code

THANKS and may the functions be with you !