
рдпрд╣ рд▓реЗрдЦ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдФрд░ рдЖрд░рдПрдХреНрд╕рдЬреЗрдПрд╕ рдХреЗ рд╕рд╛рде рдЕрдиреБрднрд╡ рд╡рд╛рд▓реЗ рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рд╣реИред рдореИрдВ рд╕рд┐рд░реНрдл рдРрд╕реЗ рдЯреЗрдореНрдкрд▓реЗрдЯ рд╕рд╛рдЭрд╛ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдЬреЛ рдореБрдЭреЗ рдРрд╕реЗ рдпреВрдЖрдИ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧреА рд▓рдЧреЗред
рдпрд╣рд╛рдБ рд╣рдо рдХреНрдпрд╛ рдХрд░рддреЗ рд╣реИрдВ:

рдХрдХреНрд╖рд╛рдУрдВ рдХреЗ рдмрд┐рдирд╛, рдПрдХ рдЬреАрд╡рдирдЪрдХреНрд░ рдпрд╛ setState
рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛ред
рдЯреНрд░реЗрдирд┐рдВрдЧ
рдЖрдк рд╕рднреА рдХреА рдЬрд░реВрд░рдд GitHub рдкрд░ рдореЗрд░реЗ рднрдВрдбрд╛рд░ рдореЗрдВ рд╣реИред
git clone https://github.com/yazeedb/recompose-github-ui cd recompose-github-ui yarn install
master
рд╢рд╛рдЦрд╛ рдореЗрдВ рдПрдХ рддреИрдпрд╛рд░ рдкрд░рд┐рдпреЛрдЬрдирд╛ рд╣реИред рдпрджрд┐ рдЖрдк рдЪрд░рдг рджрд░ рдЪрд░рдг рдЬрд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рддреЛ start
рдмреНрд░рд╛рдВрдЪ рдкрд░ рдЬрд╛рдПрдБред
git checkout start
рдФрд░ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдЪрд▓рд╛рддреЗ рд╣реИрдВред
npm start
рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ localhost:3000
рдкрд░ рд╢реБрд░реВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП localhost:3000
рдФрд░ рдпрд╣рд╛рдВ рд╣рдорд╛рд░рд╛ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдпреВрдЖрдИ рд╣реИред

рдЕрдкрдирд╛ рдкрд╕рдВрджреАрджрд╛ рд╕рдВрдкрд╛рджрдХ рд▓реЙрдиреНрдЪ рдХрд░реЗрдВ рдФрд░ src/index.js
рдЦреЛрд▓реЗрдВред

рд╕рдВрдпреЛрдЬрд┐рдд
рдпрджрд┐ рдЖрдк Recompose рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рдирд╣реАрдВ рд╣реИрдВ, рддреЛ рдпрд╣ рдПрдХ рдЕрджреНрднреБрдд рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╣реИ рдЬреЛ рдЖрдкрдХреЛ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рд╢реИрд▓реА рдореЗрдВ React рдШрдЯрдХ рдмрдирд╛рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдЗрд╕рдореЗрдВ рдХрд╛рд░реНрдпреЛрдВ рдХрд╛ рдПрдХ рдмрдбрд╝рд╛ рд╕реЗрдЯ рд╣реЛрддрд╛ рд╣реИред рдпрд╣рд╛рдБ рдореЗрд░реЗ рдкрд╕рдВрджреАрджрд╛ рд╣реИрдВред
рдпрд╣ рд▓реЛрджрд╛рд╢ / рд░рд╛рдорджрд╛ рдХреА рддрд░рд╣ рд╣реИ, рдХреЗрд╡рд▓ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХрд░реЗрдВред
рдореБрдЭреЗ рдмрд╣реБрдд рдЦреБрд╢реА рд╣реИ рдХрд┐ рдпрд╣ рдСрдмреНрдЬрд░реНрд╡рд░ рдкреИрдЯрд░реНрди рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИред рдкреНрд░рд▓реЗрдЦрди рдЙрджреНрдзреГрдд рдХрд░рддреЗ рд╣реБрдП:
рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ рдХрд┐ рдЕрдзрд┐рдХрд╛рдВрд╢ рд░рд┐рдПрдХреНрдЯрд░ рдШрдЯрдХ рдПрдкреАрдЖрдИ рдСрдмреНрдЬрд░реНрд╡рд░ рдкреИрдЯрд░реНрди рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ рд╡реНрдпрдХреНрдд рдХрд┐рдП рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВред
рдЖрдЬ рд╣рдо рдЗрд╕ рдЕрд╡рдзрд╛рд░рдгрд╛ рдХрд╛ рдЕрднреНрдпрд╛рд╕ рдХрд░реЗрдВрдЧреЗ!
рдЗрдирд▓рд╛рдЗрди рдШрдЯрдХ
рдЕрдм рддрдХ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ App
- рд╕рдмрд╕реЗ рдЖрдо рдШрдЯрдХ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ред Recompose рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╕реЗ ComponentsFromStream рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╣рдо рдЗрд╕реЗ рдПрдХ рдСрдмреНрдЬрд░реНрд╡реЗрдмрд▓ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
componentFromStream
рдлрд╝рдВрдХреНрд╢рди рд╣рдорд╛рд░реЗ рдЕрд╡рд▓реЛрдХрди рдпреЛрдЧреНрдп рдкреНрд░рддреНрдпреЗрдХ рдирдП рдореВрд▓реНрдп рдкрд░ рд░реЗрдВрдбрд░ рд╢реБрд░реВ рдХрд░рддрд╛ рд╣реИред рдпрджрд┐ рдЕрднреА рддрдХ рдХреЛрдИ рдореВрд▓реНрдп рдирд╣реАрдВ рд╣реИрдВ, рддреЛ рдпрд╣ null
ред
рдХрд╛ рд╡рд┐рдиреНрдпрд╛рд╕
рдкреБрди: рдкреНрд░рд╕реНрддрд╛рд╡ рдореЗрдВ рдзрд╛рд░рд╛рдПрдВ ECMAScript рдСрдмреНрдЬрд░реНрд╡реЗрдмрд▓ рдкреНрд░рд╕реНрддрд╛рд╡ рджрд╕реНрддрд╛рд╡реЗрдЬ рдХрд╛ рдкрд╛рд▓рди рдХрд░рддреА рд╣реИрдВред рдпрд╣ рд╡рд░реНрдгрди рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдЬрдм рд╡реЗ рдЖрдзреБрдирд┐рдХ рдмреНрд░рд╛рдЙрдЬрд╝рд░реЛрдВ рдореЗрдВ рд▓рд╛рдЧреВ рд╣реЛрддреЗ рд╣реИрдВ рддреЛ рдСрдмреНрдЬрд░реНрд╡ рдХрд░рдиреЗ рдпреЛрдЧреНрдп рд╡рд╕реНрддреБрдУрдВ рдХреЛ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред
рдЗрд╕ рдмреАрдЪ, рд╣рдо рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдЬреИрд╕реЗ RxJS, xstream, рдЕрдзрд┐рдХрд╛рдВрд╢, Flyd, рдЖрджрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред
рд░реАрдХрдВрдкреЛрдЬрд╝ рдХреЛ рдкрддрд╛ рдирд╣реАрдВ рд╣реИ рдХрд┐ рд╣рдо рдХрд┐рд╕ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдпрд╣ setObservableConfig
рдлрд╝рдВрдХреНрд╢рди рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдЗрд╕рдХреЗ рд╕рд╛рде, рдЖрдк рдЕрдкрдиреА рдЬрд╝рд░реВрд░рдд рдХреА рд╣рд░ рдЪреАрдЬрд╝ рдХреЛ ES рдСрдмреНрдЬрд░реНрд╡реЗрдмрд▓ рдореЗрдВ рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВред
src
рдлреЛрд▓реНрдбрд░ рдореЗрдВ рдПрдХ рдирдИ рдлрд╛рдЗрд▓ рдмрдирд╛рдПрдВ рдФрд░ рдЙрд╕реЗ observableConfig.js
рдирд╛рдо рджреЗрдВред
RxJS 6 рдХреЛ рдкреБрдирдГ рдХрдиреЗрдХреНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЗрд╕рдореЗрдВ рдирд┐рдореНрди рдХреЛрдб рд▓рд┐рдЦреЗрдВ:
import { from } from 'rxjs'; import { setObservableConfig } from 'recompose'; setObservableConfig({ fromESObservable: from });
рдЗрд╕ рдлрд╝рд╛рдЗрд▓ рдХреЛ index.js
рдореЗрдВ рдЖрдпрд╛рдд рдХрд░реЗрдВ:
import './observableConfig';
рд╡рд╣ рд╕рдм рд╣реИ!
рдкреБрди: рдкреНрд░рд╕реНрддрд╛рд╡ + RxJS
index.js
componentFromStream
index.js
рдЖрдпрд╛рдд рдЬреЛрдбрд╝реЗрдВ:
import { componentFromStream } from 'recompose';
рдЖрдЗрдП, App
рдШрдЯрдХ рдХреЛ рдУрд╡рд░рд░рд╛рдЗрдб рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░реЗрдВ:
const App = componentFromStream(prop$ => { ... });
рдХреГрдкрдпрд╛ рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ componentFromStream
рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рд╕рдорд╛рд░реЛрд╣ рдкреИрд░рд╛рдореАрдЯрд░ рд▓реЗрддрд╛ рд╣реИ prop$
рд╣реИ, рдЬреЛ рдкреНрд░рддреНрдпрдХреНрд╖ рд╕рдВрд╕реНрдХрд░рдг рд╣реИ props
ред рдЗрд╕ рд╡рд┐рдЪрд╛рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдорд╛рдирдЪрд┐рддреНрд░ рдХреЛ рд░рд┐рдПрдХреНрдЯ рдШрдЯрдХреЛрдВ рдореЗрдВ рдирд┐рдпрдорд┐рдд рд░реВрдк рд╕реЗ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд░рдирд╛ рд╣реИред
рдпрджрд┐ рдЖрдкрдиреЗ RxJS рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рд╣реИ, рддреЛ рдЖрдкрдХреЛ рдорд╛рдирдЪрд┐рддреНрд░ рдСрдкрд░реЗрдЯрд░ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред
рдирдХреНрд╢рд╛
рдЬреИрд╕рд╛ рдХрд┐ рдирд╛рдо рд╕реЗ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ, рдирдХреНрд╢рд╛ Observable(something)
рдХреЛ Observable(somethingElse)
Observable(something)
рдореЗрдВ рдмрджрд▓ рджреЗрддрд╛ рд╣реИред рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ - Observable(component)
рдореЗрдВ Observable(component)
Observable(props)
Observable(component)
ред
map
рдСрдкрд░реЗрдЯрд░ рдЖрдпрд╛рдд рдХрд░реЗрдВ:
import { map } from 'rxjs/operators';
рд╣рдорд╛рд░реЗ App
рдШрдЯрдХ рдХрд╛ рдкреВрд░рдХ:
const App = componentFromStream(prop$ => { return prop$.pipe( map(() => ( <div> <input placeholder="GitHub username" /> </div> )) ) });
RxJS 5 рдХреЗ рд╕рд╛рде, рд╣рдо рдмрдпрд╛рдиреЛрдВ рдХреА рдПрдХ рд╢реНрд░реГрдВрдЦрд▓рд╛ рдХреЗ рдмрдЬрд╛рдп pipe
рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред
рдлрд╝рд╛рдЗрд▓ рд╕рд╣реЗрдЬреЗрдВ рдФрд░ рдкрд░рд┐рдгрд╛рдо рдХреА рдЬрд╛рдБрдЪ рдХрд░реЗрдВред рдХреБрдЫ рднреА рдирд╣реАрдВ рдмрджрд▓рд╛ рд╣реИ!

рдПрдХ рдЗрд╡реЗрдВрдЯ рд╣реИрдВрдбрд▓рд░ рдЬреЛрдбрд╝реЗрдВ
рдЕрдм рд╣рдо рдЕрдкрдиреЗ рдЗрдирдкреБрдЯ рдХреНрд╖реЗрддреНрд░ рдХреЛ рдереЛрдбрд╝рд╛ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдмрдирд╛ рджреЗрдВрдЧреЗред
createEventHandler
рдЖрдпрд╛рдд рдЬреЛрдбрд╝реЗрдВ:
import { componentFromStream, createEventHandler } from 'recompose';
рд╣рдо рдЗрд╕реЗ рдЗрд╕ рддрд░рд╣ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ:
const App = componentFromStream(prop$ => { const { handler, stream } = createEventHandler(); return prop$.pipe( map(() => ( <div> <input onChange={handler} placeholder="GitHub username" /> </div> )) ) });
createEventHandler
рджреНрд╡рд╛рд░рд╛ рдмрдирд╛рдИ рдЧрдИ рд╡рд╕реНрддреБ рдХреЗ рджреЛ рджрд┐рд▓рдЪрд╕реНрдк рдХреНрд╖реЗрддреНрд░ рд╣реИрдВ: handler
рдФрд░ stream
ред
рд╣реБрдб рдХреЗ рддрд╣рдд, handler
рдПрдХ рдШрдЯрдирд╛ рдПрдорд┐рдЯрд░ рд╣реИ рдЬреЛ рдореВрд▓реНрдпреЛрдВ рдХреЛ stream
рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рддрд╛ рд╣реИред рдФрд░ stream
рдмрджрд▓реЗ рдореЗрдВ, рдПрдХ рдЕрд╡рд▓реЛрдХрди рдпреЛрдЧреНрдп рд╡рд╕реНрддреБ рд╣реИ рдЬреЛ рдЧреНрд░рд╛рд╣рдХреЛрдВ рдХреЛ рдорд╛рди рджреЗрддреА рд╣реИред
рд╣рдо рдЗрдирдкреБрдЯ рдХреНрд╖реЗрддреНрд░ рдХреЗ рд╡рд░реНрддрдорд╛рди рдореВрд▓реНрдп рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП stream
рдХреЛ рд▓рд┐рдВрдХ рдХрд░реЗрдВрдЧреЗ рдФрд░ prop$
рдХрд╛ prop$
рдХрд░реЗрдВрдЧреЗред
рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдПрдХ рдЕрдЪреНрдЫрд╛ рд╡рд┐рдХрд▓реНрдк рдПрдХ рд╕рдорд╛рд░реЛрд╣ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд╣реЛрдЧрд╛ combineLatest
ред
рдЕрдВрдбрд╛ рдФрд░ рдЪрд┐рдХрди рдХреА рд╕рдорд╕реНрдпрд╛
combineLatest
рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, stream
рдФрд░ prop$
рджреЛрдиреЛрдВ рдХреЛ рдорд╛рди рдХрд╛ рдЙрддреНрдкрд╛рджрди рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред рд▓реЗрдХрд┐рди stream
рдХреБрдЫ рднреА рдЬрд╛рд░реА рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ рдЬрдм рддрдХ рдХрд┐ рдХреБрдЫ рдореВрд▓реНрдп prop$
рдФрд░ рдЗрд╕рдХреЗ рд╡рд┐рдкрд░реАрдд рдЬрд╛рд░реА рди рдХрд░реЗрдВред
рдЖрдк stream
рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдореВрд▓реНрдп рдкрд░ stream
рд╕реЗрдЯ рдХрд░рдХреЗ рдЗрд╕реЗ рдареАрдХ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
RxJS рд╕реЗ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдХрдерди рдЖрдпрд╛рдд рдХрд░реЗрдВ:
import { map, startWith } from 'rxjs/operators';
рдЕрджреНрдпрддрди stream
рд╕реЗ рдорд╛рди рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдирдпрд╛ рдЪрд░ рдмрдирд╛рдПрдБ:
// App component const { handler, stream } = createEventHandler(); const value$ = stream.pipe( map(e => e.target.value) startWith('') );
рд╣рдо рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рдЗрдирдкреБрдЯ рдлрд╝реАрд▓реНрдб рдореЗрдВ рдмрджрд▓рд╛рд╡ рд╣реЛрдиреЗ рдкрд░ stream
рдЗрд╡реЗрдВрдЯреНрд╕ рдХреЛ рдлреЗрдВрдХ рджреЗрдЧреА, рддреЛ рдЪрд▓рд┐рдП рддреБрд░рдВрдд рдЙрдиреНрд╣реЗрдВ рдЯреЗрдХреНрд╕реНрдЯ рдореЗрдВ рдЯреНрд░рд╛рдВрд╕рд▓реЗрдЯ рдХрд░рддреЗ рд╣реИрдВред
рдФрд░ рдЪреВрдВрдХрд┐ рдЗрдирдкреБрдЯ рдлрд╝реАрд▓реНрдб рдХреЗ рд▓рд┐рдП рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдорд╛рди рдПрдХ рд░рд┐рдХреНрдд рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╣реИ, value$
рд╕рд╛рде value$
рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░реЗрдВ value$
''
рдПрдХ рд╕рд╛рде рдмреБрдирдирд╛
рдЕрдм рд╣рдо рджреЛрдиреЛрдВ рдзрд╛рд░рд╛рдУрдВ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИрдВред рдПрдХ combineLatest
рд░реВрдк рдореЗрдВ, combineLatest
рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдмрдирд╛рдиреЗ рдХреА рдПрдХ рд╡рд┐рдзрд┐ рдХреЗ рд░реВрдк рдореЗрдВ combineLatest
рдХреЛ рдЗрдореНрдкреЛрд░реНрдЯ рдХрд░реЗрдВред
import { combineLatest } from 'rxjs';
рдЖрдк рдЗрдирдкреБрдЯ рдорд╛рдиреЛрдВ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ tap
рд╕реНрдЯреЗрдЯрдореЗрдВрдЯ рднреА рдЖрдпрд╛рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
import { map, startWith, tap } from 'rxjs/operators';
рдЗрд╕реЗ рдЗрд╕ рддрд░рд╣ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ:
const App = componentFromStream(prop$ => { const { handler, stream } = createEventHandler(); const value$ = stream.pipe( map(e => e.target.value), startWith('') ); return combineLatest(prop$, value$).pipe( tap(console.warn),
рдЕрдм, рдпрджрд┐ рдЖрдк рд╣рдорд╛рд░реЗ рдЗрдирдкреБрдЯ рдХреНрд╖реЗрддреНрд░ рдореЗрдВ рдХреБрдЫ рд▓рд┐рдЦрдирд╛ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдХрдВрд╕реЛрд▓ рдореЗрдВ [props, value]
рджрд┐рдЦрд╛рдИ рджреЗрдВрдЧреЗред

рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдШрдЯрдХ
рдпрд╣ рдШрдЯрдХ рдЙрд╕ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд╝рд┐рдореНрдореЗрджрд╛рд░ рд╣реЛрдЧрд╛ рдЬрд┐рд╕рдХрд╛ рдирд╛рдо рд╣рдо рдЙрд╕реЗ рд╣рд╕реНрддрд╛рдВрддрд░рд┐рдд рдХрд░реЗрдВрдЧреЗред рдпрд╣ App
рдШрдЯрдХ рд╕реЗ value
рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдЧрд╛ рдФрд░ рдЗрд╕реЗ AJAX рдЕрдиреБрд░реЛрдз рдореЗрдВ рдЕрдиреБрд╡рд╛рдж рдХрд░реЗрдЧрд╛ред
рдЬреЗрдПрд╕рдПрдХреНрд╕ / рд╕реАрдПрд╕рдПрд╕
рдпрд╣ рд╕рдм рдЕрджреНрднреБрдд GitHub рдХрд╛рд░реНрдб рдкрд░рд┐рдпреЛрдЬрдирд╛ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рд╣реИред рдЕрдзрд┐рдХрд╛рдВрд╢ рдХреЛрдб, рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рд╢реИрд▓рд┐рдпреЛрдВ рдХреЛ рдХреЙрдкреА рдпрд╛ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
src/User
рдлрд╝реЛрд▓реНрдбрд░ рдмрдирд╛рдПрдБред рдЗрд╕рдореЗрдВ рдПрдХ User.css
рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдБ рдФрд░ рдЗрд╕ рдХреЛрдб рдХреЛ рдЗрд╕рдореЗрдВ рдХреЙрдкреА рдХрд░реЗрдВ ред
рдФрд░ рдЗрд╕ рдХреЛрдб рдХреЛ src/User/Component.js
рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдХреЙрдкреА рдХрд░реЗрдВ ред
рдпрд╣ рдШрдЯрдХ рдмрд╕ рдХреЙрд▓ рд╕реЗ GitHub рдПрдкреАрдЖрдИ рдХреЗ рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЛ рдкреЙрдкреНрдпреБрд▓реЗрдЯ рдХрд░рддрд╛ рд╣реИред
рдкрд╛рддреНрд░
рдЕрдм рдпрд╣ рдШрдЯрдХ "рдЧреВрдВрдЧрд╛" рд╣реИ рдФрд░ рд╣рдо рд╕рдбрд╝рдХ рдкрд░ рдирд╣реАрдВ рд╣реИрдВ, рдЪрд▓реЛ рдПрдХ "рд╕реНрдорд╛рд░реНрдЯ" рдШрдЯрдХ рдмрдирд╛рддреЗ рд╣реИрдВред
рдпрд╣рд╛рдБ src/User/index.js
import React from 'react'; import { componentFromStream } from 'recompose'; import { debounceTime, filter, map, pluck } from 'rxjs/operators'; import Component from './Component'; import './User.css'; const User = componentFromStream(prop$ => { const getUser$ = prop$.pipe( debounceTime(1000), pluck('user'), filter(user => user && user.length), map(user => ( <h3>{user}</h3> )) ); return getUser$; }); export default User;
рд╣рдордиреЗ User
рдХреЛ componentFromStream
рд░реВрдк рдореЗрдВ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛, рдЬреЛ рдПрдХ рдСрдмреНрдЬрд░реНрд╡реЗрдмрд▓ prop$
рд╡рд╕реНрддреБ рджреЗрддрд╛ рд╣реИ рдЬреЛ рдЖрдиреЗ рд╡рд╛рд▓реА рд╕рдВрдкрддреНрддрд┐рдпреЛрдВ рдХреЛ <h3>
рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рддрд╛ рд╣реИред
debounceTime
рд╣рдорд╛рд░реЗ User
рдХреЛ рдХреАрдмреЛрд░реНрдб рдкрд░ рд╣рд░ рдмрд╛рд░ рдХреБрдВрдЬреА рджрдмрд╛рдиреЗ рдкрд░ рдирдП рдорд╛рди рдкреНрд░рд╛рдкреНрдд рд╣реЛрдВрдЧреЗ, рд▓реЗрдХрд┐рди рд╣рдореЗрдВ рдЗрд╕ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред
рдЬрдм рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЯрд╛рдЗрдк рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░рддрд╛ рд╣реИ, рддреЛ debounceTime(1000)
рдЙрди рд╕рднреА рдШрдЯрдирд╛рдУрдВ рдХреЛ рдЫреЛрдбрд╝ рджреЗрдЧрд╛ рдЬреЛ рдПрдХ рд╕реЗрдХрдВрдб рд╕реЗ рдХрдо рд╕рдордп рддрдХ рдЪрд▓рддреА рд╣реИрдВред
рд╕рд╛рд╣рд╕
рд╣рдо рдЙрдореНрдореАрдж рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ user
рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ props.user
рд░реВрдк рдореЗрдВ рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ props.user
ред рдкреНрд▓рдХ рдСрдкрд░реЗрдЯрд░ рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реЗ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдлрд╝реАрд▓реНрдб рд▓реЗрддрд╛ рд╣реИ рдФрд░ рдЙрд╕рдХрд╛ рдореВрд▓реНрдп рд▓реМрдЯрд╛рддрд╛ рд╣реИред
рдлрд┐рд▓реНрдЯрд░
рдпрд╣рд╛рдВ рд╣рдо рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ user
рдкрд╛рд░рд┐рдд рд╣реЛ рдЧрдпрд╛ рд╣реИ рдФрд░ рдЦрд╛рд▓реА рд╕реНрдЯреНрд░рд┐рдВрдЧ рдирд╣реАрдВ рд╣реИред
рдирдХреНрд╢рд╛
рд╣рдо user
рд╕реЗ <h3>
рдЯреИрдЧ рдмрдирд╛рддреЗ рд╣реИрдВред
Hooking
src/index.js
рд╡рд╛рдкрд╕ src/index.js
рдФрд░ User
рдШрдЯрдХ рдЖрдпрд╛рдд рдХрд░реЗрдВ:
import User from './User';
рд╣рдо user
рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд░реВрдк рдореЗрдВ рдореВрд▓реНрдп value
рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ:
return combineLatest(prop$, value$).pipe( tap(console.warn), map(([props, value]) => ( <div> <input onChange={handler} placeholder="GitHub username" /> <User user={value} /> </div> )) );
рдЕрдм рд╣рдорд╛рд░рд╛ рдорд╛рди рдПрдХ рд╕реЗрдХрдВрдб рдХреА рджреЗрд░реА рд╕реЗ рдкреНрд░рджрд░реНрд╢рд┐рдд рд╣реЛрддрд╛ рд╣реИред

рдмреБрд░рд╛ рдирд╣реАрдВ рд╣реИ, рдЕрдм рд╣рдореЗрдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рдбреЗрдЯрд╛ рдЕрдиреБрд░реЛрдз
GitHub рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреА рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдПрдкреАрдЖрдИ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ: https://api.github.com/users/$endersuser} ред рд╣рдо рдЖрд╕рд╛рдиреА рд╕реЗ рдПрдХ рд╕рд╣рд╛рдпрдХ рд╕рдорд╛рд░реЛрд╣ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ:
const formatUrl = user => `https://api.github.com/users/${user}`;
рдФрд░ рдЕрдм рд╣рдо filter
рдмрд╛рдж map(formatUrl)
рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ:
const getUser$ = prop$.pipe( debounceTime(1000), pluck('user'), filter(user => user && user.length), map(formatUrl),
рдФрд░ рдЕрдм, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдирд╛рдо рдХреЗ рдмрдЬрд╛рдп, рд╕реНрдХреНрд░реАрди URL рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИред
рд╣рдореЗрдВ рдПрдХ рдЕрдиреБрд░реЛрдз рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ! switchMap
рдФрд░ ajax
switchMap
рд▓рд┐рдП рдЖрддреЗ рд╣реИрдВред
switchMap
рдпрд╣ рдСрдкрд░реЗрдЯрд░ рдХрдИ рдЕрд╡рд▓реЛрдХрди рдХреЗ рдмреАрдЪ рд╕реНрд╡рд┐рдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрджрд░реНрд╢ рд╣реИред
рдорд╛рди рд▓реЗрдВ рдХрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдиреЗ рдирд╛рдо рдЯрд╛рдЗрдк рдХрд┐рдпрд╛ рд╣реИ, рдФрд░ рд╣рдо switchMap
рдЕрдВрджрд░ рдПрдХ рдЕрдиреБрд░реЛрдз switchMap
ред
рдпрджрд┐ рдПрдкреАрдЖрдИ рд╕реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдЖрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреБрдЫ рджрд░реНрдЬ рдХрд░рддрд╛ рд╣реИ рддреЛ рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИ? рдХреНрдпрд╛ рд╣рдореЗрдВ рдкрд┐рдЫрд▓реЗ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЪрд┐рдВрддрд┐рдд рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП?
рдирд╣реАрдВред
switchMap
рдкреБрд░рд╛рдиреЗ рдЕрдиреБрд░реЛрдз рдХреЛ рд░рджреНрдж рдХрд░реЗрдЧрд╛ рдФрд░ рдирдП рдкрд░ рд╕реНрд╡рд┐рдЪ рдХрд░реЗрдЧрд╛ред
ajax
RxJS рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ ajax
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ рдЬреЛ switchMap
рд╕рд╛рде рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ!
рдХреЛрд╢рд┐рд╢
рд╣рдо рджреЛрдиреЛрдВ рдСрдкрд░реЗрдЯрд░реЛрдВ рдХреЛ рдЖрдпрд╛рдд рдХрд░рддреЗ рд╣реИрдВред рдореЗрд░рд╛ рдХреЛрдб рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:
import { ajax } from 'rxjs/ajax'; import { debounceTime, filter, map, pluck, switchMap } from 'rxjs/operators';
рдФрд░ рдЙрдиреНрд╣реЗрдВ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ:
const User = componentFromStream(prop$ => { const getUser$ = prop$.pipe( debounceTime(1000), pluck('user'), filter(user => user && user.length), map(formatUrl), switchMap(url => ajax(url).pipe( pluck('response'), map(Component) ) ) ); return getUser$; });
switchMap
рд╣рдорд╛рд░реЗ рдЗрдирдкреБрдЯ рдлрд╝реАрд▓реНрдб рд╕реЗ AJAX рдЕрдиреБрд░реЛрдз рдкрд░ рд╕реНрд╡рд┐рдЪ рдХрд░рддрд╛ рд╣реИред рдЬрдм рдХреЛрдИ рдЙрддреНрддрд░ рдЖрддрд╛ рд╣реИ, рддреЛ рд╡рд╣ рдЗрд╕реЗ рд╣рдорд╛рд░реЗ рдбрдВрдмрд▓ рдШрдЯрдХ рдореЗрдВ рднреЗрдЬ рджреЗрддрд╛ рд╣реИред
рдФрд░ рдпрд╣рд╛рдБ рдкрд░рд┐рдгрд╛рдо рд╣реИ!

рд╣реИрдВрдбрд▓рд┐рдВрдЧ рдореЗрдВ рддреНрд░реБрдЯрд┐
рдПрдХ рдирдХреНрд╕рд▓реА рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдирд╛рдо рджрд░реНрдЬ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВред

рд╣рдорд╛рд░рд╛ рдЖрд╡реЗрджрди рдЯреВрдЯ рдЧрдпрд╛ рд╣реИред
catchError
catchError
рдСрдкрд░реЗрдЯрд░ рдХреЗ рд╕рд╛рде catchError
рд╣рдо рдЪреБрдкрдЪрд╛рдк catchError
рдмрдЬрд╛рдп рдПрдХ рд╢рд╛рдВрдд рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рд╣рдо рдЖрдпрд╛рдд рдХрд░рддреЗ рд╣реИрдВ:
import { catchError, debounceTime, filter, map, pluck, switchMap } from 'rxjs/operators';
рдФрд░ рдЗрд╕реЗ рд╣рдорд╛рд░реЗ AJAX рдЕрдиреБрд░реЛрдз рдХреЗ рдЕрдВрдд рдореЗрдВ рдбрд╛рд▓реЗрдВ:
switchMap(url => ajax(url).pipe( pluck('response'), map(Component), catchError(({ response }) => alert(response.message)) ) )

рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдмреБрд░рд╛ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдЖрдк рдмреЗрд╣рддрд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рдШрдЯрдХ рддреНрд░реБрдЯрд┐
рд╕рд╛рдордЧреНрд░реА рдХреЗ рд╕рд╛рде src/Error/index.js
рдмрдирд╛рдПрдБ:
import React from 'react'; const Error = ({ response, status }) => ( <div className="error"> <h2>Oops!</h2> <b> {status}: {response.message} </b> <p>Please try searching again.</p> </div> ); export default Error;
рдпрд╣ рдЕрдЪреНрдЫреА рддрд░рд╣ status
рд╣рдорд╛рд░реЗ AJAX рдЕрдиреБрд░реЛрдз рдХреА response
рдФрд░ status
рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдЧрд╛ред
рд╣рдо рдЗрд╕реЗ User/index.js
рдореЗрдВ рдЖрдпрд╛рдд рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ RxJS рд╕реЗ рдСрдкрд░реЗрдЯрд░ рдХреЗ рдСрдкрд░реЗрдЯрд░:
import Error from '../Error'; import { of } from 'rxjs';
рдпрд╛рдж рд░рдЦреЗрдВ рдХрд┐ рдлрдВрдХреНрд╢рди componentFromStream
рдХреЛ рдкрд╛рд╕ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдЬреЛ рдЕрд╡рд▓реЛрдХрди рдпреЛрдЧреНрдп рд╣реИред рд╣рдо рдСрдкрд░реЗрдЯрд░ рдХреЗ рдЙрдкрдпреЛрдЧ рд╕реЗ рдЗрд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
ajax(url).pipe( pluck('response'), map(Component), catchError(error => of(<Error {...error} />)) )
рдЕрдм рд╣рдорд╛рд░рд╛ UI рдмрд╣реБрдд рдмреЗрд╣рддрд░ рд╣реИ:

рд╕рдВрдХреЗрддрдХ рд▓реЛрдб рд╣реЛ рд░рд╣рд╛ рд╣реИ
рд░рд╛рдЬреНрдп рдкреНрд░рдмрдВрдзрди рдХрд╛ рдкрд░рд┐рдЪрдп рджреЗрдиреЗ рдХрд╛ рд╕рдордп рдЖ рдЧрдпрд╛ рд╣реИред рдЖрдк рд▓реЛрдбрд┐рдВрдЧ рдЗрдВрдбрд┐рдХреЗрдЯрд░ рдХреЛ рдФрд░ рдХреИрд╕реЗ рд▓рд╛рдЧреВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ?
рдХреНрдпрд╛ рд╣реЛрдЧрд╛ рдЕрдЧрд░ рдЬрдЧрд╣ setState
рд╣рдо BehaviorSubject
рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ?
рдкреБрди : рдкреНрд░рд╕реНрддрд╛рд╡рд┐рдд рдкреНрд░рд▓реЗрдЦрди рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕реБрдЭрд╛рд╡ рджреЗрддрд╛ рд╣реИ:
SetState () рдХреЗ рдмрдЬрд╛рдп, рдХрдИ рдереНрд░реЗрдбреНрд╕ рд╕рдВрдпреЛрдЬрд┐рдд рдХрд░реЗрдВ
рдареАрдХ рд╣реИ, рдЖрдкрдХреЛ рджреЛ рдирдП рдЖрдпрд╛рдд рдЪрд╛рд╣рд┐рдП:
import { BehaviorSubject, merge, of } from 'rxjs';
BehaviorSubject
рдореЗрдВ рдбрд╛рдЙрдирд▓реЛрдб рд╕реНрдерд┐рддрд┐ рд╣реЛрдЧреА, рдФрд░ merge
рдЗрд╕реЗ рдШрдЯрдХ рдХреЗ рд╕рд╛рде рдЬреЛрдбрд╝ рджреЗрдЧрд╛ред
componentFromStream
рдЕрдВрджрд░
const User = componentFromStream(prop$ => { const loading$ = new BehaviorSubject(false); const getUser$ = ...
рдПрдХ BehaviorSubject
рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдореВрд▓реНрдп, рдпрд╛ "рд╕реНрдерд┐рддрд┐" рдХреЗ рд╕рд╛рде рдЖрд░рдВрднреАрдХреГрдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЪреВрдВрдХрд┐ рд╣рдо рдХреБрдЫ рднреА рдирд╣реАрдВ рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдЬрдм рддрдХ рдХрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдкрд╛рда рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рдирд╛ рд╢реБрд░реВ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рддрдм рддрдХ рдпрд╣ false
ред
рд╣рдо tap
рдСрдкрд░реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ loading$
рд╕реНрдерд┐рддрд┐ рдХреЛ рдмрджрд▓ рджреЗрдВрдЧреЗ:
import { catchError, debounceTime, filter, map, pluck, switchMap, tap
рд╣рдо рдЗрд╕реЗ рдЗрд╕ рддрд░рд╣ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ:
const loading$ = new BehaviorSubject(false); const getUser$ = prop$.pipe( debounceTime(1000), pluck('user'), filter(user => user && user.length), map(formatUrl), tap(() => loading$.next(true)), // <--- switchMap(url => ajax(url).pipe( pluck('response'), map(Component), tap(() => loading$.next(false)), // <--- catchError(error => of(<Error {...error} />)) ) ) );
switchMap
рдФрд░ AJAX рдЕрдиреБрд░реЛрдз рдХреЗ рдареАрдХ рдкрд╣рд▓реЗ, рд╣рдо loading$
рдореВрд▓реНрдп рдХреЗ рд▓рд┐рдП true
, рдФрд░ рд╕рдлрд▓ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рдмрд╛рдж false
ред
рдФрд░ рдЕрдм рд╣рдо loading$
рдФрд░ getUser$
рдХрдиреЗрдХреНрдЯ рдХрд░рддреЗ рд╣реИрдВред
return merge(loading$, getUser$).pipe( map(result => (result === true ? <h3>Loading...</h3> : result)) );
рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐ рд╣рдо рдХрд╛рдо рджреЗрдЦреЗрдВ, рд╣рдо delay
рд╡рд┐рд╡рд░рдг рдХреЛ рдЖрдпрд╛рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рддрд╛рдХрд┐ рд╕рдВрдХреНрд░рдордг рдмрд╣реБрдд рддреЗрдЬрд╝ рди рд╣реЛрдВред
import { catchError, debounceTime, delay, filter, map, pluck, switchMap, tap } from 'rxjs/operators';
map(Component)
рд╕реЗ рдкрд╣рд▓реЗ delay
рдЬреЛрдбрд╝реЗрдВ map(Component)
:
ajax(url).pipe( pluck('response'), delay(1500), map(Component), tap(() => loading$.next(false)), catchError(error => of(<Error {...error} />)) )
рдкрд░рд┐рдгрд╛рдо?

рд╕рднреА :)