![](https://media.slid.es/uploads/364812/images/2495328/_____________.jpg)
ABOUT US
![](https://media.slid.es/uploads/364812/images/2434259/leadscanr_promo.png)
LeadScanr - finds leads from social media in real-time
Front-End, ML
Full stack
Ievgen Terpil
Vyacheslav Pytel
![](https://media.slid.es/uploads/364812/images/2485068/P1020678.jpg)
![](https://media.slid.es/uploads/364812/images/2485020/DSC_5351.jpg)
chapter 0
INTRO
INITIAL POINT
- Framework without improvements
- File structure
- Scalability
- Build tools
![](https://media.slid.es/uploads/364812/images/2423867/feels.png)
IDEAL APP
- framework with community
- easy to implement new features
- easy to support
- easy to test
- localization
- build tools
chapter 1
HYPE
![](https://media.slid.es/uploads/364812/images/2487566/Hype-Logo-Turq.jpg)
FLUX
![](https://media.slid.es/uploads/364812/images/2473907/ARCH-Classic-Flux__2_.png)
REduX
![](https://media.slid.es/uploads/364812/images/2435376/flux-growth-comparison.png)
![](https://media.slid.es/uploads/364812/images/2435384/reacteurope.png)
![](https://media.slid.es/uploads/364812/images/2435390/9VsY9i09_400x400.jpeg)
React Europe
REduX
(state, action) => state
![](https://media.slid.es/uploads/364812/images/2484555/ARCH-Redux2.png)
REDUX
![](https://media.slid.es/uploads/364812/images/2484552/ARCH-Redux2-real.gif)
REduX
{
type: 'DEPOSIT',
value: 10
}
Action
![](https://media.slid.es/uploads/364812/images/2484437/ARCH-Redux2-actions.png)
REduX
function counter(state = 0, action) {
switch (action.type) {
case 'DEPOSIT':
return state + action.value
case 'WITHDRAW':
return state - action.value
default:
return state
}
}
Reducer
![](https://media.slid.es/uploads/364812/images/2484438/ARCH-Redux2-reducer.png)
Changes are made with pure functions
REduX
State
state tree
![](https://media.slid.es/uploads/364812/images/2484470/ARCH-Redux2-store.png)
Single source of truth
REduX
const store =
createStore(reducer, initialState)
store.subscribe(render)
// -----------------------------------
store.dispatch(action)
STore
![](https://media.slid.es/uploads/364812/images/2484470/ARCH-Redux2-store.png)
State is read-only
REduX
const App = ({ state }) => {
<div>
Balance: {state}
</div>
}
VIEW
![](https://media.slid.es/uploads/364812/images/2484545/ARCH-Redux2-view.png)
VIEW LAYER
........
![](https://media.slid.es/uploads/364812/images/1654497/pasted-from-clipboard.png)
![](https://media.slid.es/uploads/364812/images/2428670/139426.png)
REACT AS VIEW LAYER
![](https://media.slid.es/uploads/364812/images/2484577/Redux-react-in.png)
REACT AS VIEW LAYER
Account = ({ balance, onDepositClick }) => {
<div>
<button onClick={onDepositClick}>
deposit
</button>
<div>Balance: {balance}</div>
</div>
}
REACT AS VIEW LAYER
connect(
mapStateToProps,
mapDispatchToProps
)(Account)
function mapStateToProps(state, ownProps) {
return { balance: state.balance }
}
function mapDispatchToProps(dispatch) {
return {
onDepositClick: () => dispatch(deposit())
}
}
![](https://media.slid.es/uploads/364812/images/2487525/6630715205091328.jpg)
REACT AS VIEW LAYER
@connect(({ Subscriptions, Profile }) => ({
currentPlan: Subscriptions.get('currentPlan'),
userName: Profile.get('userName')
}))
export default class Subscriptions extends React.Component {
static propTypes = {
dispatch: PropTypes.func.isRequired,
userName: PropTypes.string,
currentPlan: PropTypes.object
}
...
}
our case with ES7
decorator
DUMB AND SMART
Dumb (Presentational)
Smart (Container)
logic
Redux's connect
binds cb for dumb
DOM markup and styles
reusable
your mini Bootstrap
SIDE EFFECTS
![](https://media.slid.es/uploads/364812/images/2484714/ARCH-Redux2-extended-api.png)
SIDE EFFECTS
![](https://media.slid.es/uploads/364812/images/2484716/ARCH-Redux2-extended-real.gif)
SIDE EFFECTS - BASE APPROACH
{ type: 'FETCH_ACCOUNT_REQUEST' }
{ type: 'FETCH_ACCOUNT_SUCCESS', account: { ... } }
{ type: 'FETCH_ACCOUNT_FAILURE', error: 'Oops' }
actions
action creators
function receiveAccount(account) {
return {
type: FETCH_ACCOUNT_SUCCESS,
account
}
}
SIDE EFFECTS - BASE APPROACH
let getAccount = id => dispatch => {
dispatch(requestAccount(id));
return fetch('/account', id)
.then(account => dispatch(receiveAccount(account)))
.catch(error => dispatch(throwError(error)));
};
complex action creator
API request
import { CALL_API } from `redux-api-middleware`;
{
[CALL_API]: {
endpoint: 'api/account',
method: 'GET',
types: ['REQUEST', 'SUCCESS', 'FAILURE']
}
}
action creators
SIDE EFFECTS - LESS BOILERPLATE
declarative
SIDE EFFECTS - LESS BOILERPLATE
![](https://media.slid.es/uploads/364812/images/2484790/ARCH-Redux2-extended-real-declerative.gif)
chapter 2
PRODUCTION
![](https://media.slid.es/uploads/364812/images/2487568/lsp_managing-phantom-pain_181114-065724.jpg)
FEATURE FOLDERS
![](https://media.slid.es/uploads/364812/images/2434438/ff.png)
FEATURE FOLDERS
![](https://media.slid.es/uploads/364812/images/2434438/ff.png)
view
actions
reducers
i
i
i
feature1
feature2
feature3
FEATURE FOLDERS
![](https://media.slid.es/uploads/364812/images/2434438/ff.png)
view
actions
reducers
i
i
i
feature1
feature2
feature3
set of standart components
FEATURE FOLDERS
![](https://media.slid.es/uploads/364812/images/2434438/ff.png)
view
actions
reducers
i
i
i
feature1
feature2
feature3
set of standart components
main reducer
FEATURE FOLDERS
![](https://media.slid.es/uploads/364812/images/2434438/ff.png)
view
actions
reducers
i
i
i
feature1
feature2
feature3
set of standart components
main reducer
all actions
FEATURE FOLDERS
our solutions
import reducers from './features/**/reducers.js';
yo redux-component
import actions from './features/**/actions.js';
account/
Account.jsx
actions.js
reducres.js
button/
Button.jsx
b-button.scss
Smart (feature)
Dump
- if it receives a promise, it will dispatch the resolved value of the promise
export function getAccount() {
return async (api) => {
return {
type: events.ACCOUNT_READY,
account: await api.options.account.get()
};
};
}
our case with ES7
SIDE EFFECTS - ADVANCED USAGE
Action Creator
Service 1
Service 2
Service 3
A
A
A
SIDE EFFECTS - ADVANCED USAGE
Action Creator
Service 1
Service 2
Service 3
A
A
A
SIDE EFFECTS - ADVANCED USAGE
Action Creator
Action Creator
SIDE EFFECTS - ADVANCED USAGE
![](https://media.slid.es/uploads/364812/images/2484734/dispatcher.png)
applyMiddlewares(middleware1, middleware2, ...)
dispatch([
startProcessCard(),
setCreditCard(card),
getOffers(),
buy(plan.get('id')),
pushState(null, '/account', {})
]);
async waterfall
SIDE EFFECTS - ADVANCED USAGE
chapter 3
SAGA
![](https://media.slid.es/uploads/364812/images/2487528/p0232nkj.jpg)
SAGA
orchestrating complex/asynchronous operations
Saga
Service 1
Service 2
Service 3
REDUX-SAGA
Generator functions (ES6) as action creators
1
function* fetchAccount() {
const account = yield Api.fetch('/account')
console.log(account)
}
function* watchFetchAccount() {
yield* takeEvery('ACCOUNT_REQUESTED', fetchAccount)
}
REDUX-SAGA
Declarative Effects
{
CALL: {
fn: Api.fetch,
args: ['./account']
}
}
2
yield only a description of
the function invocation
import { call } from 'redux-saga/effects'
function* fetchAccount() {
const account = yield call(Api.fetch, '/account')
// ...
}
- making our code testable
REDUX-SAGA
Dispatching actions
import { call } from 'redux-saga/effects'
function* fetchAccount(dispatch) {
const account = yield call(Api.fetch, '/account')
dispatch({ type: 'ACCOUNT_RECEIVED', account })
}
import { call, put } from 'redux-saga/effects'
function* fetchAccount() {
const account = yield call(Api.fetch, '/account')
yield put({ type: 'ACCOUNT_RECEIVED', products })
}
REDUX-SAGA
Testing
const iterator = fetchAccount()
assert.deepEqual(
iterator.next().value,
call(Api.fetch, '/account')
)
// create a fake response
const account = { balance: 10 }
// expects a dispatch instruction
assert.deepEqual(
iterator.next(account).value,
put({ type: 'ACCOUNT_RECEIVED', account })
)}
REDUX-SAGA API
takeEvery
takeLatest
Saga
take
put
call
A
Api
Dispatcher
fork
Saga
cancel
CONCLUSION
flux
redux
redux:
(state, action) => state
CONCLUSION
flux
redux
redux:
(state, action) => state
use feature folders
create collection of Dumb components
side-effects:
easy
complex
redux-thunk
redux-promise
redux-saga
i
THANK YOU FOR YOUR ATTENTION
Ievgen Terpil
Vyacheslav Pytel
![](https://media.slid.es/uploads/364812/images/2484320/twitter-bird.png)
![](https://media.slid.es/uploads/364812/images/2484320/twitter-bird.png)
![](https://media.slid.es/uploads/364812/images/2484329/github.png)
![](https://media.slid.es/uploads/364812/images/2484329/github.png)
![](https://media.slid.es/uploads/364812/images/2434259/leadscanr_promo.png)
Redux. From twitter hype to production
By Jenya Terpil
Redux. From twitter hype to production
- 64,692