react, reactrouter, redux, redux-observable · renderdays() { let days =...
Post on 22-May-2020
26 Views
Preview:
TRANSCRIPT
React, ReactRouter, Redux, redux-observable
Алексей ОхрименкоIPONWEB, Москва
Алексей Охрименко
?
IPONWEB
14
React компоненты
create-react-app calendar
render() { return [ <div className="month"> <ul> <li className="prev">❮</li> <li className="next">❯</li> <li><div>August</div><span>2017</span></li> </ul> </div>, <ul className="weekdays"> <li>Mo</li> </ul>, <ul className="days"> <li>1</li> </ul> ]; }
render() { return [ <div className="month"> <ul> <li className="prev">❮</li> <li className="next">❯</li> <li><div>August</div><span>2017</span></li> </ul> </div>, <ul className="weekdays"> <li>Mo</li> </ul>, <ul className="days"> <li>1</li> </ul> ]; }
render() { return [ <div className="month"> <ul> <li className="prev">❮</li> <li className="next">❯</li> <li><div>August</div><span>2017</span></li> </ul> </div>, <ul className="weekdays"> <li>Mo</li> </ul>, <ul className="days"> <li>1</li> </ul> ]; }
render() { return [ <div className="month"> <ul> <li className="prev">❮</li> <li className="next">❯</li> <li><div>August</div><span>2017</span></li> </ul> </div>, <ul className="weekdays"> <li>Mo</li> </ul>, <ul className="days"> <li>1</li> </ul> ]; }
render() { return [ <div className="month"> <ul> <li className="prev">❮</li> <li className="next">❯</li> <li><div>August</div><span>2017</span></li> </ul> </div>, <ul className="weekdays"> <li>Mo</li> </ul>, <ul className="days"> <li>1</li> </ul> ]; }
constructor() { super(); let now = new Date(); this.state = { year: now.getFullYear(), month: now.getMonth() + 1 } this.next = this.next.bind(this); this.prev = this.prev.bind(this); }
constructor() { super(); let now = new Date(); this.state = { year: now.getFullYear(), month: now.getMonth() + 1 } this.next = this.next.bind(this); this.prev = this.prev.bind(this); }
next() { this.setState(getNextYearMonth(this.state.year, this.state.month)); } prev() { this.setState(getPrevYearMonth(this.state.year, this.state.month)); }
render() { return [ <div className="month"> <ul> <li className="prev">❮</li> <li className="next">❯</li> <li><div>August</div><span>2017</span></li> </ul> </div>, <ul className="weekdays"> <li>Mo</li> </ul>, <ul className="days"> <li>1</li> </ul> ]; }
<div className="month" key="month"> <ul> <li onClick={this.prev} className="prev">❮</li> <li onClick={this.next} className="next">❯</li> <li> <div>{getFullMonthName(this.state.month)}</div> <div>{this.state.year}</div> </li> </ul> </div>,
<div className="month" key="month"> <ul> <li onClick={this.prev} className="prev">❮</li> <li onClick={this.next} className="next">❯</li> <li> <div>{getFullMonthName(this.state.month)}</div> <div>{this.state.year}</div> </li> </ul> </div>,
<ul className="weekdays" key="weekdays"> <li>Mo</li> <li>Tu</li> <li>We</li> <li>Th</li> <li>Fr</li> <li>Sa</li> <li>Su</li> </ul>,
this.renderDays()
renderDays() { let days = getDaysInMonth(this.state.year, this.state.month); let skip = getFirstDayWeekday(this.state.year, this.state.month); let items = new Array(days).fill().map((_, index) => { let cls = index === 0 ? 'skip' + skip : ''; return <li className={cls} key={index}>{index + 1}</li> }); return ( <ul className="days" key="days"> {items} </ul> ) }
renderDays() { let days = getDaysInMonth(this.state.year, this.state.month); let skip = getFirstDayWeekday(this.state.year, this.state.month); let items = new Array(days).fill().map((_, index) => { let cls = index === 0 ? 'skip' + skip : ''; return <li className={cls} key={index}>{index + 1}</li> }); return ( <ul className="days" key="days"> {items} </ul> ) }
renderDays() { let days = getDaysInMonth(this.state.year, this.state.month); let skip = getFirstDayWeekday(this.state.year, this.state.month); let items = new Array(days).fill().map((_, index) => { let cls = index === 0 ? 'skip' + skip : ''; return <li className={cls} key={index}>{index + 1}</li> }); return ( <ul className="days" key="days"> {items} </ul> ) }
renderDays() { let days = getDaysInMonth(this.state.year, this.state.month); let skip = getFirstDayWeekday(this.state.year, this.state.month); let items = new Array(days).fill().map((_, index) => { let cls = index === 0 ? 'skip' + skip : ''; return <li className={cls} key={index}>{index + 1}</li> }); return ( <ul className="days" key="days"> {items} </ul> ) }
let items = new Array(days).map(() => 1)
let items = new Array(days).fill().map(() => 1)
null, undefined
null, undefined, undefined value
renderDays() { let days = getDaysInMonth(this.state.year, this.state.month); let skip = getFirstDayWeekday(this.state.year, this.state.month); let items = new Array(days).fill().map((_, index) => { let cls = index === 0 ? 'skip' + skip : ''; return <li className={cls} key={index}>{index + 1}</li> }); return ( <ul className="days" key="days"> {items} </ul> ) }
renderDays() { let days = getDaysInMonth(this.state.year, this.state.month); let skip = getFirstDayWeekday(this.state.year, this.state.month); let items = new Array(days).fill().map((_, index) => { let cls = index === 0 ? 'skip' + skip : ''; return <li className={cls} key={index}>{index + 1}</li> }); return ( <ul className="days" key="days"> {items} </ul> ) }
renderDays() { let days = getDaysInMonth(this.state.year, this.state.month); let skip = getFirstDayWeekday(this.state.year, this.state.month); let items = new Array(days).fill().map((_, index) => { let cls = index === 0 ? 'skip' + skip : ''; return <li className={cls} key={index}>{index + 1}</li> }); return ( <ul className="days" key="days"> {items} </ul> ) }
constructor() { super(); let now = new Date(); this.state = { year: now.getFullYear(), weekNumber: getWeekNumber(now) } this.next = this.next.bind(this); this.prev = this.prev.bind(this); }
constructor() { super(); let now = new Date(); this.state = { year: now.getFullYear(), weekNumber: getWeekNumber(now) } this.next = this.next.bind(this); this.prev = this.prev.bind(this); }
constructor() { super(); let now = new Date(); this.state = { year: now.getFullYear(), month: now.getMonth() + 1 } this.next = this.next.bind(this); this.prev = this.prev.bind(this); }
constructor() { super(); let now = new Date(); this.state = { year: now.getFullYear(), weekNumber: getWeekNumber(now) } this.next = this.next.bind(this); this.prev = this.prev.bind(this); }
constructor() { super(); let now = new Date(); this.state = { year: now.getFullYear(), month: now.getMonth() + 1 } this.next = this.next.bind(this); this.prev = this.prev.bind(this); }
CalendarContainer.js
constructor() { super(); let now = new Date(); this.state = { year: now.getFullYear(), month: now.getMonth() + 1, weekNumber: getWeekNumber(now) } }
Container / Page / Atomic Design
constructor() { super(); let now = new Date(); this.state = { year: now.getFullYear(), month: now.getMonth() + 1, weekNumber: getWeekNumber(now) } }
CalendarContainer.js
return [ <Month year={this.state.year} month={this.state.month}></Month>, <Week year={this.state.year} month={this.state.weekNumber}></Week> ];
Умные/Глупые компоненты
Коммуникация между компонентами
React
ROOT
TARGET
Components Props
Коммуникация между компонентами
React
ROOT
TARGET
Components Props
Коммуникация между компонентами
React
ROOT
TARGET
Components Props
Коммуникация между компонентами
React
ROOT
TARGET
Components Props
React Router - на рану
import { BrowserRouter } from 'react-router-dom'
ReactDOM.render(( <BrowserRouter> <App /> </BrowserRouter> ), document.getElementById('root'))
<Switch> <Route exact path='/' component={Month}/> <Route path='/week' component={Week}/> </Switch>
Кто не использует Router?
… у вас возможно уважительные причины
«About Page»
Состояние приложения
Состояние приложения != Состояние компонента
Состояние приложения != this.setState
Cостояние
Состояние приложения - это одно из главных отличий Frontend от Backend
https://www.youtube.com/watch?v=udNHwANuicU
State Managers
Redux
Dan Abramov
Данила Абрамов
Коммуникация между компонентами
React
ROOT
TARGET
Коммуникация между компонентами
React
ROOT
TARGET
Store
ReduxDispatch
Коммуникация между компонентами
React
ROOT
TARGET
Store
ReduxDispatch
Subscribe
Коммуникация между компонентами
React
ROOT
TARGET
Store
ReduxDispatch
Subscribe
Умные/Глупые компоненты все-равно нужно использовать
Увы в коде ничего проще не становиться
Reducers, Action, Store, ActionCreators синхронны :(
SideEffect Managers
SideEffect Managers
●thunk ●redux-saga ●redux-loop ●redux-observable
SideEffect Managers
●thunk ●redux-saga ●redux-loop ●redux-observable
Promise
function a() { return 1; }
function b() { return a() + 2; }
console.log(b());
function a() { return 1; }
function b() { return a() + 2; }
console.log(b());
function a() { return 1; }
function b() { return a() + 2; }
console.log(b());
function a() { return new Promise((resolve, reject) => { resolve(1); }); }
function b() { return a().then((v) => v + 2); }
b().then(console.log)
function a() { return new Promise((resolve, reject) => { resolve(1); }); }
function b() { return a().then((v) => v + 2); }
b().then(console.log)
function a() { return new Promise((resolve, reject) => { resolve(1); }); }
function b() { return a().then((v) => v + 2); }
b().then(console.log)
Проблемы Promise
●Одно значение
Проблемы Promise
●Одно значение ●Отмена
Проблемы Promise
●Одно значение ●Отмена ●Повтор
Проблемы Promise
●Одно значение ●Отмена ●Повтор ●Отсутствие синхронности
Проблемы Promise
●Одно значение ●Отмена ●Повтор ●Отсутствие синхронности ●Finally *
Observable
function a() { return [1]; }
function b() { return a().map((v) => v + 2); }
console.log(b());
function a() { return [1]; }
function b() { return a().map((v) => v + 2); }
console.log(b());
function a() { return [1]; }
function b() { return a().map((v) => v + 2); }
console.log(b());
function a() { return Observable.create(function(next, error, done) { next(1); done(); }); }
function b() { return a().map((v) => v + 2); }
b().subscribe(console.log);
function a() { return Observable.create(function(next, error, done) { next(1); done(); }); }
function b() { return a().map((v) => v + 2); }
b().subscribe(console.log);
function a() { return Observable.create(function(next, error, done) { next(1); done(); }); }
function b() { return a().map((v) => v + 2); }
b().subscribe(console.log);
map, filter, scan
function a() { return Observable.create(function(next, error, done) { next(1); done(); }); }
function b() { return a().map((v) => v + 2); }
b().subscribe(console.log);
delay, debounce, throttle
function a() { return Observable.create(function(next, error, done) { next(1); done(); }); }
function b() { return a().map((v) => v + 2); }
b().subscribe(console.log);
function a() { return Observable.create(function(next, error, done) { next(1); done(); }); }
function b() { return a().map((v) => v + 2); }
b().subscribe(console.log);
function a() { return Observable.create(function(next, error, done) { next(1); done(); }); }
function b() { return a().map((v) => v + 2); }
b().subscribe(console.log);
Hot vs Cold
Higher Order Observable
Promise.all, Promise.race
function a() { return Observable.create(function(next, error, done) { next(1); next(2); done(); }); }
function b() { return a().switchMap((v) => ajax.get('/api')); }
b().subscribe(console.log);
function a() { return Observable.create(function(next, error, done) { next(1); next(2); done(); }); }
function b() { return a().switchMap((v) => ajax.get('/api')); }
b().subscribe(console.log);
function a() { return Observable.create(function(next, error, done) { next(1); next(2); done(); }); }
function b() { return a().switchMap((v) => ajax.get('/api')); }
b().subscribe(console.log);
function a() { return Observable.create(function(next, error, done) { next(1); next(2); done(); }); }
function b() { return a().switchMap((v) => ajax.get('/api')); }
b().subscribe(console.log);
function a() { return Observable.create(function(next, error, done) { next(1); next(2); done(); }); }
function b() { return a().switchMap((v) => ajax.get('/api')); }
b().subscribe(console.log);
function a() { return Observable.create(function(next, error, done) { next(1); next(2); done(); }); }
function b() { return a().switchMap((v) => ajax.get('/api')); }
b().subscribe(console.log);
RxJs - это lodash для Observableъ
> 130 методов
redux-observable
import { ajax } from 'rxjs/observable/dom/ajax';
const fetchEpic = action$ => action$.ofType(FETCH) .switchMap(action => ajax.getJSON(`/api/${action.payload}`) .map(response => fetchFulfilled(response)) .catch(error => Observable.of({ type: FETCH_REJECTED, payload: error.xhr.response, error: true })) );
import { ajax } from 'rxjs/observable/dom/ajax';
const fetchEpic = action$ => action$.ofType(FETCH) .switchMap(action => ajax.getJSON(`/api/${action.payload}`) .map(response => fetchFulfilled(response)) .catch(error => Observable.of({ type: FETCH_REJECTED, payload: error.xhr.response, error: true })) );
import { ajax } from 'rxjs/observable/dom/ajax';
const fetchEpic = action$ => action$.ofType(FETCH) .switchMap(action => ajax.getJSON(`/api/${action.payload}`) .map(response => fetchFulfilled(response)) .catch(error => Observable.of({ type: FETCH_REJECTED, payload: error.xhr.response, error: true })) );
import { ajax } from 'rxjs/observable/dom/ajax';
const fetchEpic = action$ => action$.ofType(FETCH) .switchMap(action => ajax.getJSON(`/api/${action.payload}`) .map(response => fetchFulfilled(response)) .catch(error => Observable.of({ type: FETCH_REJECTED, payload: error.xhr.response, error: true })) );
import { ajax } from 'rxjs/observable/dom/ajax';
const fetchEpic = action$ => action$.ofType(FETCH) .switchMap(action => ajax.getJSON(`/api/${action.payload}`) .map(response => fetchFulfilled(response)) .catch(error => Observable.of({ type: FETCH_REJECTED, payload: error.xhr.response, error: true })) );
import { ajax } from 'rxjs/observable/dom/ajax';
const fetchEpic = action$ => action$.ofType(FETCH) .switchMap(action => ajax.getJSON(`/api/${action.payload}`) .map(response => fetchFulfilled(response)) .catch(error => Observable.of({ type: FETCH_REJECTED, payload: error.xhr.response, error: true })) );
import { ajax } from 'rxjs/observable/dom/ajax';
const fetchEpic = action$ => action$.ofType(FETCH) .switchMap(action => ajax.getJSON(`/api/${action.payload}`) .map(response => fetchFulfilled(response)) .catch(error => Observable.of({ type: FETCH_REJECTED, payload: error.xhr.response, error: true })) );
Очень умная очередь запросов
.debounce(1000)
.distinctUntilChanged()
.switchMap(…)
Дожидаемся реальных изменений
.retry(3)
500
.retryWhen(function (errors) { return Observable .zip( Observable.range(1, MAX_RETRIES), errors, (i, e) => i ) .flatMap((i) => Observable.timer(i * 1000)); })
Exponential Backoff
Послесловие…
1) React компоненты (create-react-app)
1) React компоненты (create-react-app) 2) Умные/Глупые компоненты
1) React компоненты (create-react-app) 2) Умные/Глупые компоненты 3) Router
1) React компоненты (create-react-app) 2) Умные/Глупые компоненты 3) Router 4) State Manager ( Redux … )
1) React компоненты (create-react-app) 2) Умные/Глупые компоненты 3) Router 4) State Manager ( Redux … ) 5) Redux -> SideEffect Manager -> ReduxObservable
1) React компоненты (create-react-app) 2) Умные/Глупые компоненты 3) Router 4) State Manager ( Redux … ) 5) Redux -> SideEffect Manager -> ReduxObservable 6) Observable / 2 > Promise
Twitter: Ai_boy http://bit.ly/2G05fuo
Алексей Охрименко
top related