рдЬреАрд╡рди рд╕реЗ рджреБрдЦ

рд╢реБрдн рджрд┐рдиред


рдХреНрдпрд╛ рдЖрдкрдХреЗ рдкрд╛рд╕ рдПрдХ рдкрд░рд┐рдЪрд┐рдд рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдбреЗрд╡рд▓рдкрд░ рднреА рд╣реИ рдЬреЛ Redux рдореЗрдВ рджреБрд╖реНрдкреНрд░рднрд╛рд╡реЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЖрд╢реНрдЪрд░реНрдпрдЬрдирдХ рдХрд╣рд╛рдирд┐рдпрд╛рдВ рдмрддрд╛рддрд╛ рд╣реИ? рдирд╣реАрдВ! рдХреНрдпрд╛ рдореИрдВ рдпрд╣ рд╡реНрдпрдХреНрддрд┐ рдмрди рд╕рдХрддрд╛ рд╣реВрдБ



рд▓реЗрдЦрдХ рдиреЗ рд╕реНрд╡рддрдВрддреНрд░рддрд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ рдкрд░рд┐рдЪрдпрд╛рддреНрдордХ рднрд╛рдЧ рдирд╣реАрдВ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рд▓рд┐рдпрд╛ рдЬреЛ рдХрд┐ redux рдЧрд╛рдерд╛ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╣реИред рдЙрдиреНрд╣реЗрдВ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдЕрдкрд░реНрдпрд╛рдкреНрдд рдбреЗрдЯрд╛ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдПрдХ рдЙрджрд╛рд░ рдкрд╛рдардХ Habr рдЦреЛрдЬ рдпрд╛ рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдЧрд╛ред рд╕рд╛рд░ рдХреЛ рд╡реНрдпрдХреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдпреЗ рдЙрджрд╛рд╣рд░рдг рдмрд╣реБрдд рд╕рд░рд▓ рд╣реИрдВред


рддреЛ, рдореИрдВрдиреЗ рдЖрдк рд╕рднреА рдХреЛ рдПрдХ рд╕рд╛рде рдХреНрдпреЛрдВ рд░рдЦрд╛ред рдпрд╣ рдореБрдХрд╛рдмрд▓рд╛ рдЧреНрд░рд╛рд╣рдХреЛрдВ рдХреЗ рдЦреБрд▓реЗ рд╕реНрдерд╛рдиреЛрдВ рдореЗрдВ рд░реЗрдбрдХреНрд╕ рдЧрд╛рдерд╛ рдХреЗ рдЙрдкрдпреЛрдЧ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╣реЛрдЧрд╛ред рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ, "рд╕реНрд╡реАрдХрд╛рд░ рдХрд╛рд░реНрд░рд╡рд╛рдИ => рднреЗрдЬреЗрдВ рдПрдкреАрдЖрдИ рдЕрдиреБрд░реЛрдз => рдПрдХ рдирдИ рдХрд╛рд░реНрд░рд╡рд╛рдИ рдмрдирд╛рдПрдБ" рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рдФрд░ рджрд┐рд▓рдЪрд╕реНрдк рдорд╛рдорд▓реЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВред


рдореБрдЭреЗ рд╕рд╛рдереА рдирд╛рдЧрд░рд┐рдХреЛрдВ рджреНрд╡рд╛рд░рд╛ рдЗрд╕ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ рдЧрд╣рди рдЕрдзреНрдпрдпрди рдХреЛ рдкреНрд░реЛрддреНрд╕рд╛рд╣рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╢рд╛ рд╣реИ, рд╕рд╛рде рд╣реА рд╕рд╛рде рдпрд╣ рднреА рдмрддрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рдХрд┐ рдХреИрд╕реЗ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдЪреАрдЬреЗрдВ рдЕрдзрд┐рдХ рд╕рдордЭрдиреЗ рдпреЛрдЧреНрдп рдФрд░ рдЕрднрд┐рд╡реНрдпрдВрдЬрдХ рдмрди рдЬрд╛рддреА рд╣реИрдВред


WebSockets


рдЙрдкрдпреЛрдЧ рдХрд╛ рдорд╛рдорд▓рд╛: рдкреБрд╢ рдореЙрдбрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕рдордп рдореЗрдВ рд╕рд░реНрд╡рд░ рд╕реЗ рдЙрдкрд▓рдмреНрдз рд░рд┐рдХреНрддрд┐рдпреЛрдВ рдХреА рд╕реВрдЪреА рдХреЗ рдЕрдкрдбреЗрдЯ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВред


рдпрд╣ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рд╡реЗрдм рд╕реЙрдХреЗрдЯ рдХреЗ рдЙрдкрдпреЛрдЧ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, socket.io рдХреЛ рд▓реЗрдВ, рд▓реЗрдХрд┐рди рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╕реЙрдХреЗрдЯ рдПрдкреАрдЖрдИ рдпрд╣рд╛рдВ рдХреЛрдИ рдорд╛рдпрдиреЗ рдирд╣реАрдВ рд░рдЦрддрд╛ рд╣реИред


рд╕рдЧрд╕ рдореЗрдВ рдЪреИрдирд▓ рдЬреИрд╕реА рдХреЛрдИ рдЪреАрдЬ рд╣реЛрддреА рд╣реИред рдпрд╣ рдПрдХ рд╕рдВрджреЗрд╢ рдмрд╕ рд╣реИ рдЬрд┐рд╕рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдШрдЯрдирд╛рдУрдВ рдХрд╛ рд╕реНрд░реЛрдд рдЕрдкрдиреЗ рдЙрдкрднреЛрдХреНрддрд╛ рдХреЗ рд╕рд╛рде рд╕рдВрд╡рд╛рдж рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдЪреИрдирд▓реЛрдВ рдХрд╛ рдореБрдЦреНрдп рдЙрджреНрджреЗрд╢реНрдп рд╕рд╛рдЧрд╛рдУрдВ рдХреЗ рдмреАрдЪ рд╕рдВрдЪрд╛рд░ рд╣реИ рдФрд░ рдХрд╛рдо рдХреЗ рд▓рд┐рдП рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдШрдЯрдирд╛рдУрдВ рдХреА рдзрд╛рд░рд╛ рдХреЛ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рдирд╛ рд╣реИред


рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ, рд╕реНрдЯреЛрд░ redux рдЧрд╛рдерд╛ рдХреЗ рд▓рд┐рдП рдореБрдЦреНрдп рдИрд╡реЗрдВрдЯ рдЪреИрдирд▓ рд╣реИред рдШрдЯрдирд╛рдПрдБ рдХреНрд░рд┐рдпрд╛ рдХреЗ рд░реВрдк рдореЗрдВ рд╕рд╛рдордиреЗ рдЖрддреА рд╣реИрдВред рдЪреИрдирд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рд╕реНрдЯреЛрд░ рд╕реЗ рдирд╣реАрдВ рдШрдЯрдирд╛рдУрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред


рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ рдХрд┐ рдЪреИрдирд▓ рд╕рд┐рд░реНрдл рд╡рд╣реА рд╣реИ рдЬреЛ рдЖрдкрдХреЛ рд╕реЙрдХреЗрдЯ рд╕реЗ рд╕рдВрджреЗрд╢реЛрдВ рдХреА рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдзрд╛рд░рд╛ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЬрд┐рддрдиреА рдЬрд▓реНрджреА рд╣реЛ рд╕рдХреЗ рдЪреИрдирд▓ рдмрдирд╛рдПрдВ!


рд▓реЗрдХрд┐рди рдкрд╣рд▓реЗ, рдПрдХ рд╕реЙрдХреЗрдЯ рдмрдирд╛рдПрдВ:


import io from 'socket.io-client'; export const socket = io.connect('/'); 

рдЕрдм рдШрдЯрдирд╛рдУрдВ рдХреА рдПрдХ рдорд╛рдореВрд▓реА рд╕реВрдЪреА рдШреЛрд╖рд┐рдд рдХрд░реЗрдВ:


 export const SocketEvents = { jobsFresh: 'jobs+fresh', }; 

рдЕрдЧрд▓рд╛ рдПрдХ рдЪреИрдирд▓ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдХрд╛рд░рдЦрд╛рдирд╛ рд╡рд┐рдзрд┐ рд╣реИред рдХреЛрдб рд╕реЙрдХреЗрдЯ рд╕реЗ рд╣рдореЗрдВ рдмреНрдпрд╛рдЬ рдХреА рдШрдЯрдирд╛рдУрдВ рдХреА рд╕рджрд╕реНрдпрддрд╛ рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд┐рдзрд┐ рдмрдирд╛рддрд╛ рд╣реИ, рд╕рджрд╕реНрдпрддрд╛ рд╕рдорд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд┐рдзрд┐ рдФрд░, рд╕реАрдзреЗ, рдШрдЯрдирд╛ рдЪреИрдирд▓ рдЦреБрдж:


 import { eventChannel } from 'redux-saga'; import { socket } from '../apis/socket'; import { SocketEvents } from '../constants/socket-events'; export function createFreshJobsChannel() { const subscribe = emitter => { socket.on(SocketEvents.jobsFresh, emitter); return () => socket.removeListener(SocketEvents.jobsFresh, emitter); }; return eventChannel(subscribe); } 

рдЪрд▓реЛ рдПрдХ рдХрд╛рдлреА рд╕рд░рд▓ рдЧрд╛рдерд╛ рд▓рд┐рдЦрддреЗ рд╣реИрдВ, рд╕реЙрдХреЗрдЯ рд╕реЗ рдЕрдкрдбреЗрдЯ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдЗрд╕реА рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░ рд░рд╣реЗ рд╣реИрдВ:


 import { take, call, put } from 'redux-saga/effects'; import { createFreshJobsChannel } from '../channels/fresh-jobs'; import { JobsActions } from '../actions/jobs'; export function * freshJobsSaga() { const channel = yield call(createFreshJobsChannel); while (true) { const jobs = yield take(channel); const action = JobsActions.fresh(jobs); yield put(action); } } 

рдЗрд╕реЗ рдХреЗрд╡рд▓ рдореВрд▓ рдЧрд╛рдерд╛ рд╕реЗ рдмрд╛рдВрдзрдирд╛ рд╢реЗрд╖ рд╣реИ:


 import { fork } from 'redux-saga/effects'; import { freshJobsSaga } from './fresh-jobs'; export function * sagas() { yield fork(freshJobsSaga); } 

Google рд╕реНрдерд╛рди рд╕реНрд╡рддрдГ рдкреВрд░реНрдг


рдорд╛рдорд▓реЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ: рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рдкрд╛рд╕ рдЕрдЪрд▓ рд╕рдВрдкрддреНрддрд┐ рдХреЗ рд▓рд┐рдП рдмрд╛рдж рдХреА рдЦреЛрдЬ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдПрдХ рднреМрдЧреЛрд▓рд┐рдХ рд╕реНрдерд╛рди рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рдиреЗ рдкрд░ рдпреБрдХреНрддрд┐рдпрд╛рдВ рджрд┐рдЦрд╛рдПрдВред


рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рд╣рдореЗрдВ рдирд┐рд░реНрджреЗрд╢рд╛рдВрдХ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рд╡рд╛рдВрдЫрд┐рдд рдХреНрд╖реЗрддреНрд░ рдХреЗ рдорд╛рдирд╡-рдкрдардиреАрдп рдирд╛рдо рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред


рдпрд╣ рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдХрд╛рд░реНрдп рдмреЛрд░рд┐рдВрдЧ "рдПрдХреНрд╢рди => рдПрдкреАрдЖрдИ => рдПрдХреНрд╢рди" рд╕реЗ рдХреИрд╕реЗ рднрд┐рдиреНрди рд╣реИ? рдСрдЯреЛ-рдкреВрд░реНрдг рд╣реЛрдиреЗ рдХреА рд╕реНрдерд┐рддрд┐ рдореЗрдВ, рд╣рдо рдмрд╛рд╣рд░реА рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреЗ рд▓рд┐рдП рдпрдерд╛рд╕рдВрднрд╡ рдмреЗрдХрд╛рд░ рдХреЙрд▓ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдХреЗрд╡рд▓ рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рд╕рдВрдХреЗрдд рднреА рджрд┐рдЦрд╛ рд╕рдХрддреЗ рд╣реИрдВред


рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо Google рд╕реНрдерд╛рди рд╕реНрд╡рдд: рдкреВрд░реНрдг рд╕реЗрд╡рд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рдПрдХ рдПрдкреАрдЖрдИ рд╡рд┐рдзрд┐ рд▓рд┐рдЦреЗрдВрдЧреЗред рдпрд╣рд╛рдБ рджрд┐рд▓рдЪрд╕реНрдк рдмрд╛рддреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рджреЗрд╢ рдХреЗ рднреАрддрд░ рд╕рдВрдХреЗрддреЛрдВ рдХреА рд╕реАрдорд╛ рд╣реИ:


 export function getPlaceSuggestions(autocompleteService, countryCode, query) { return new Promise(resolve => { autocompleteService.getPlacePredictions({ componentRestrictions: { country: countryCode }, input: query, }, resolve); }); } 

рдПрдХ рдПрдкреАрдЖрдИ рд╡рд┐рдзрд┐ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рдЦреАрдВрдЪреЗрдВрдЧреЗ, рдЖрдк рдПрдХ рдЧрд╛рдерд╛ рд▓рд┐рдЦрдирд╛ рд╢реБрд░реВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╣ рдмреЗрдХрд╛рд░ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рд╕реНрдкрд╖реНрдЯ рдХрд░рдиреЗ рдХрд╛ рд╕рдордп рд╣реИред


рдорд╛рдереЗ рдореЗрдВ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди, рдЬрдм рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдкреНрд░рдХрд╛рд░, рдФрд░ рд╣рдо рдкреНрд░рддреНрдпреЗрдХ рдкрд░рд┐рд╡рд░реНрддрди рдХреЗ рд▓рд┐рдП, рдкрдврд╝рддреЗ рд╣реИрдВ - рдкреНрд░рддреНрдпреЗрдХ рд╡рд░реНрдг рдХреЗ рд▓рд┐рдП, рдПрдкреАрдЖрдИ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрдиреБрд░реЛрдз рднреЗрдЬреЗрдВ - рдХрд╣реАрдВ рдирд╣реАрдВ рдЬрд╛рддрд╛ рд╣реИред рдЬрдм рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЯрд╛рдЗрдк рдХрд░ рд░рд╣рд╛ рд╣реЛрддрд╛ рд╣реИ, рддреЛ рдЙрд╕реЗ рд╕рдВрдХреЗрдд рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИред рд▓реЗрдХрд┐рди рдЬрдм рд╡рд╣ рд░реБрдХ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдЙрд╕рдХреА рд╕реЗрд╡рд╛ рдХрд░рдиреЗ рдХрд╛ рд╕рдордп рдЖ рдЬрд╛рддрд╛ рд╣реИред


рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╣рдо рдРрд╕реА рд╕реНрдерд┐рддрд┐ рдореЗрдВ рдирд╣реАрдВ рд░рд╣рдирд╛ рдЪрд╛рд╣реЗрдВрдЧреЗ рдЬрд╣рд╛рдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдиреЗ рдХреБрдЫ рдЯрд╛рдЗрдк рдХрд┐рдпрд╛ рд╣реЛ, рд░реБрдХ рдЧрдпрд╛ рд╣реЛ, рдПрдкреАрдЖрдИ рдЕрдиреБрд░реЛрдз рдЪрд▓рд╛ рдЧрдпрд╛ рд╣реЛ, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдХреБрдЫ рдЯрд╛рдЗрдк рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рджреВрд╕рд░рд╛ рдЕрдиреБрд░реЛрдз рдЪрд▓рд╛ рдЧрдпрд╛ рдерд╛ред


рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдордиреЗ рджреЛ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рдмреАрдЪ рдПрдХ рджреМрдбрд╝ рдмрдирд╛рдИред рдШрдЯрдирд╛рдПрдВ рджреЛ рддрд░рд╣ рд╕реЗ рд╡рд┐рдХрд╕рд┐рдд рд╣реЛ рд╕рдХрддреА рд╣реИрдВ рдФрд░ рджреЛрдиреЛрдВ рдмрд╣реБрдд рд╕реБрдЦрдж рдирд╣реАрдВ рд╣реИрдВред


рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ рдЕрдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рдЕрдиреБрд░реЛрдз рд╡рд░реНрддрдорд╛рди рд╕реЗ рдкрд╣рд▓реЗ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЬрд╛рдПрдЧрд╛ рдФрд░ рдПрдХ рдкрд▓ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рд╕рдВрдХреЗрддреЛрдВ рдХреЛ рджреЗрдЦреЗрдЧрд╛ред рдЕрдкреНрд░рд┐рдп, рд▓реЗрдХрд┐рди рдорд╣рддреНрд╡рдкреВрд░реНрдг рдирд╣реАрдВред


рдпрд╛, рд╡рд░реНрддрдорд╛рди рдЕрдиреБрд░реЛрдз рдЕрдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рдПрдХ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдкрд╣рд▓реЗ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдмреНрд▓рд┐рдВрдХ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдЙрд╕реА рдЕрдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рд╕рдВрдХреЗрддреЛрдВ рдХреЗ рд╕рд╛рде рд░рд╣реЗрдЧрд╛ред рдпрд╣ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИред


рдмреЗрд╢рдХ, рд╣рдо рдЗрд╕ рддрд░рд╣ рдХреА рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдкрд╣рд▓реЗ рдирд╣реАрдВ рд╣реИрдВ рдФрд░ рдмрд╣рд╕ рдХреЗ рд░реВрдк рдореЗрдВ рдЬрд╛рдиреА рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рддрдХрдиреАрдХ рд╕реЗ рд╣рдореЗрдВ рдорджрдж рдорд┐рд▓реЗрдЧреА - рдЕрдВрддрд┐рдо рдШрдЯрдирд╛ рдХреЗ рдмрд╛рдж рдПрди рд╕рдордп рдХреА рдЗрдХрд╛рдЗрдпреЛрдВ рдХреЗ рдмрд╛рдж рд╣реА рдХрд╛рд░реНрдп рдирд┐рд╖реНрдкрд╛рджрдиред рдпрд╣рд╛рдБ рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рдереЛрдбрд╝реА рд╕рд╛рдордЧреНрд░реА рд╣реИред


Redux рдЧрд╛рдерд╛ рдореЗрдВ, рдЗрд╕ рддрдХрдиреАрдХ рдХреЛ рджреЛ рдкреНрд░рднрд╛рд╡реЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ - рд╡рд┐рд▓рдВрдм рдФрд░ рд▓реЗрдЯрд▓реИрд╕реНрдЯ ред рдкрд╣рд▓реЗ рдПрдХ рдорд┐рд▓рд┐рд╕реЗрдХрдВрдб рдХреА рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╕рдВрдЦреНрдпрд╛ рджреНрд╡рд╛рд░рд╛ рдЧрд╛рдерд╛ рдХреЗ рдирд┐рд╖реНрдкрд╛рджрди рдХреЛ рд╕реНрдердЧрд┐рдд рдХрд░ рджреЗрддрд╛ рд╣реИред рджреВрд╕рд░рд╛ рдПрдХ рдирдИ рдШрдЯрдирд╛ рдЖрдиреЗ рдкрд░ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХрд╛рдо рдХрд░ рд░рд╣реА рдЧрд╛рдерд╛ рдХреЗ рдирд┐рд╖реНрдкрд╛рджрди рдореЗрдВ рдмрд╛рдзрд╛ рдбрд╛рд▓рддрд╛ рд╣реИред


рдпрд╣ рд╕рдм рдЬрд╛рдирддреЗ рд╣реБрдП, рд╣рдо рдПрдХ рдЧрд╛рдерд╛ рд▓рд┐рдЦреЗрдВрдЧреЗ:


 import { delay } from 'redux-saga'; import { put, call, select } from 'redux-saga/effects'; import { PlaceActions } from '../actions/place'; import { MapsActions } from '../actions/maps'; import { getPlaceSuggestions } from '../api/get-place-suggestions'; export function placeSuggestionsSaga * ({ payload: query }) { const { maps: { isApiLoaded } } = yield select(); //  API    , //      if (!isApiLoaded) { yield take(MapsActions.apiLoaded); } //     Google Places Autocomplete  store const { maps: { autocompleteService }, countryCode } = yield select(); //    , //        if (query) { yield put(PlaceActions.suggestions([])); yield put(PlaceActions.select(null)); return; } //  250    yield call(delay, 250); //  API  const suggestions = yield call( getPlaceSuggestions, autocompleteService, countryCode, query, ); //  action   const action = PlacesActions.suggestions(suggestions || []); //     store yield put(action); }; 

рдкрд┐рдЫрд▓реЗ рдЙрджрд╛рд╣рд░рдг рдХреА рддрд░рд╣, рдпрд╣ рдХреЗрд╡рд▓ рдЗрд╕реЗ рдореВрд▓ рдЧрд╛рдерд╛ рд╕реЗ рдмрд╛рдВрдзрдиреЗ рдХреЗ рд▓рд┐рдП рдмрдиреА рд╣реБрдИ рд╣реИ:


 import { takeLatest } from 'redux-saga/effects'; import { PlaceActions } from '../actions/place'; import { placeSuggestionsSaga } from './place-suggestions'; export function * sagas() { yield takeLatest( PlaceActions.changeQuery, placeSuggestionsSaga, ); } 


рдорд╛рдорд▓реЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ: рдирд┐рдпрдВрддреНрд░рдг рдХреЗ рдХреНрд╖реЗрддреНрд░ рдХреЗ рдмрд╛рд╣рд░ рдХреНрд▓рд┐рдХ рдХрд░рдиреЗ рдкрд░ рд╕реНрд╡-рд▓рд┐рдЦрд┐рдд рдбреНрд░реЙрдк-рдбрд╛рдЙрди рд╕реВрдЪреА рдмрдВрдж рдХрд░реЗрдВред


рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдпрд╣ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдЪрдпрди рдореЗрдВ рдирд┐рд░реНрдорд┐рдд рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд╛ рдЕрдиреБрдХрд░рдг рд╣реИред рдЬрд┐рди рдХрд╛рд░рдгреЛрдВ рд╕реЗ рдЖрдкрдХреЛ divs рдкрд░ рд▓рд┐рдЦреА рдЧрдИ рдбреНрд░реЙрдк-рдбрд╛рдЙрди рд╕реВрдЪреА рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛ рд╕рдХрддреА рд╣реИ, рдЙрдиреНрд╣реЗрдВ рдкрд╛рдардХ рдХреА рдХрд▓реНрдкрдирд╛ рдХреЗ рд▓рд┐рдП рдЫреЛрдбрд╝ рджрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред


рд╣рд▓ рдХрд┐рдП рдЬрд╛ рд░рд╣реЗ рдХрд╛рд░реНрдп рдХреА рдПрдХ рдкреНрд░рдореБрдЦ рд╡рд┐рд╢реЗрд╖рддрд╛ рдирд┐рдпрдВрддреНрд░рдг рд╕реЗ рдмрд╛рд╣рд░ рдХреА рдШрдЯрдирд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╕реВрдЪреА рдХреЗ рдмрд╛рд╣рд░ рдХреНрд▓рд┐рдХ рдХрд░рддреЗ рд╕рдордпред


рдЖрдк рдЕрдиреБрдорд╛рди рд▓рдЧрд╛рдпрд╛? рд╣рд╛рдВ, рдпрд╣рд╛рдВ рдЪреИрдирд▓ рднреА рд╣рдорд╛рд░реА рдорджрдж рдХрд░реЗрдВрдЧреЗред рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рд╣рдо рдЙрди рдШрдЯрдирд╛рдУрдВ рдХреЛ рдХреНрд▓рд┐рдХ рдХрд░реЗрдВрдЧреЗ, рдЬреЛ рдкреЙрдк рдЕрдк рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд╕реА рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рдкреЙрдк рдЕрдк рдХрд░рддреЗ рд╣реИрдВред


рдПрдХ рдХрд╛рд░рдЦрд╛рдирд╛ рддрд░реАрдХрд╛ рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ рдЬреЛ рдПрдХ рдордирдорд╛рдирд╛ рдЦрд┐рдбрд╝рдХреА рдШрдЯрдирд╛ рдХреЗ рд▓рд┐рдП рдЪреИрдирд▓ рдмрдирд╛рддрд╛ рд╣реИред рдФрд░ рдпрд╣рд╛рдБ рд╡рд╣ рд╣реИ:


 import { eventChannel } from 'redux-saga'; export function createWindowEventChannel(eventName) { const subscribe = emitter => { window.addEventListener(eventName, emitter); return () => window.removeEventListener(eventName, emitter); }; return eventChannel(subscribe); } 

рд╣рдо рдкрд╣рд▓реЗ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд╕рдорд╛рди рдПрдХ рдЧрд╛рдерд╛ рдмрдирд╛рддреЗ рд╣реИрдВ (рдпрджрд┐ рдЖрдк рдЪрд╛рд╣реЗрдВ рддреЛ рдЙрдирдХреЗ рд▓рд┐рдП рдПрдХ рдХрд╛рд░рдЦрд╛рдирд╛ рд╡рд┐рдзрд┐ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ):


 import { take, put, call } from 'redux-saga/effects'; import { createWindowEventChannel } from '../channels/window-event'; import { DropdownActions } from '../actions/dropdown'; export function * closeDropdownsSaga() { const channel = yield call(createWindowEventChannel, 'onClick'); while (true) { const event = yield take(channel); const action = DropdownActions.closeAll(event); yield put(action(event)); } } 

рдЗрдЪреНрдЫреБрдХ reducers рдирд┐рдпрдВрддреНрд░рдг рдХреЛ рдмрдВрдж рдЕрд╡рд╕реНрдерд╛ рдореЗрдВ рд░рдЦреЗрдВрдЧреЗ:


 import { handleActions } from 'redux-actions'; import { DropdownActions } from '../actions/dropdown'; export const priceReducer = handleActions({ ..., [DropdownActions.closeAll]: state => ({ ...state, isOpen: false}), }, {}); 

рдбреНрд░реЙрдк-рдбрд╛рдЙрди рд╕реВрдЪреА рдореЗрдВ рд╣реА рдХрд┐рд╕реА рднреА рдЖрдВрддрд░рд┐рдХ рднрд╛рдЧ рдкрд░ рдХреНрд▓рд┐рдХ рдЗрд╡реЗрдВрдЯ рдХреЗ рдкреНрд░рдЪрд╛рд░ рдХреЛ рд░реЛрдХрдирд╛ рд╣реЛрдЧрд╛ рдФрд░ рд╕рдорд╛рдкрди рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЛ рд╕реНрд╡рддрдВрддреНрд░ рд░реВрдк рд╕реЗ рд╕реНрдЯреЛрд░ рдкрд░ рднреЗрдЬрдирд╛ рд╣реЛрдЧрд╛ред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЬрдм рдЖрдк рдЦреЛрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдХреНрд▓рд┐рдХ рдХрд░рддреЗ рд╣реИрдВ:


 // components/dropdown.js import React from 'react'; export class Dropdown extends React.Component { ... __open(event) { event.stopPropagation(); this.props.open(); } } // dispatchers/open-price-dropdown.js import { DropdownActions } from '../actions/dropdown'; import { PriceActions } from '../actions/price'; export const openPriceDropdownDispatcher = dispatch => () => { dispatch( DropdownActions.closeAll() ); dispatch( PriceActions.open() ); }; 

рдЕрдиреНрдпрдерд╛, рд╕реВрдЪреА рдмрд╕ рдирд╣реАрдВ рдЦреБрд▓реЗрдЧреАред рд╡рд┐рдХрд▓реНрдк рдХрд╛ рдЪрдпрди рдХрд░рддреЗ рд╕рдордп рдХреНрд▓рд┐рдХ рдкрд░ рднреА рдпрд╣реА рдмрд╛рдд рд▓рд╛рдЧреВ рд╣реЛрддреА рд╣реИред


рдПрд▓ рдХреНрд▓реИрд╕рд┐рдХреЛ, рдЧрд╛рдерд╛ рдорд╛рдЙрдВрдЯ рдХрд░реЗрдВ:


 import { fork } from 'redux-saga/effects'; import { closeDropdownsSaga } from './close-dropdowns'; export function * sagas() { yield fork(closeDropdownsSaga); } 

рд╕реВрдЪрдирд╛рдПрдВ


рдорд╛рдорд▓реЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ: рдпрджрд┐ рдЯреИрдм рдкреГрд╖реНрдарднреВрдорд┐ рдореЗрдВ рд╣реИ, рддреЛ рдирдИ рд░рд┐рдХреНрддрд┐рдпреЛрдВ рдХреА рдЙрдкрд▓рдмреНрдзрддрд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рд╕реВрдЪрдирд╛рдПрдВ рджрд┐рдЦрд╛рдПрдВред


рд╕рдХреНрд░рд┐рдп рдЯреИрдм рдореЗрдВ, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдПрдХ рд╡рд┐рд╢реЗрд╖ рдирд┐рдпрдВрддреНрд░рдг рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рджреЗрдЦреЗрдВрдЧреЗ рдФрд░ рдЗрд╕рд▓рд┐рдП рд╕реВрдЪрдирд╛рдПрдВ рдЙрдЪрд┐рдд рдирд╣реАрдВ рд╣реИрдВред рд▓реЗрдХрд┐рди рдкреГрд╖реНрдарднреВрдорд┐ рдХреЗ рд▓рд┐рдП рдЯреИрдм рдХрд╛рдо рдЖ рд╕рдХрддрд╛ рд╣реИред рдмреЗрд╢рдХ, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреА рдЕрдиреБрдорддрд┐ рдХреЗ рд╕рд╛рде!


рдореИрдВ рдЯреИрдм рдкрд░ рдЬрд╛рдиреЗ рдФрд░ рдирдИ рд░рд┐рдХреНрддрд┐рдпреЛрдВ рдХреЛ рджрд┐рдЦрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рд╕реВрдЪрдирд╛ рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛ред рдпрджрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЬрд╡рд╛рдм рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИ, рддреЛ рдЕрдзрд┐рд╕реВрдЪрдирд╛ рдХреЛ рдмрдВрдж рдХрд░реЗрдВред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдПрдХ рдФрд░ рдЙрдкрдпреЛрдЧреА рдкреНрд░рднрд╛рд╡ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ - рджреМрдбрд╝ ред рдпрд╣ рдЖрдкрдХреЛ рдХрдИ рдЕрдиреНрдп рдкреНрд░рднрд╛рд╡реЛрдВ рдХреЗ рдмреАрдЪ рджреМрдбрд╝ рдХреА рд╡реНрдпрд╡рд╕реНрдерд╛ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдЬреНрдпрд╛рджрд╛рддрд░ рдорд╛рдорд▓реЛрдВ рдореЗрдВ, рджреМрдбрд╝ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреБрдЫ рдСрдкрд░реЗрд╢рди рдХреЗ рд▓рд┐рдП рдПрдХ рдЯрд╛рдЗрдордЖрдЙрдЯ рдкреНрд░рджрд╛рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред


рдкрд┐рдЫрд▓реЗ рдЙрджрд╛рд╣рд░рдг рд╕реЗ рдХреНрд▓рд┐рдХ рдЕрд╡рд░реЛрдзрди рдХреЛрдб рдХреЗ рд╕рд╛рде рдкрд╣рдЪрд╛рди рдХреЗ рдХрд╛рд░рдг, рд╣рдо рдЯреИрдм рдХреА рдЧрддрд┐рд╡рд┐рдзрд┐ рдХреЛ рдЯреНрд░реИрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдб рдХреЛ рдЫреЛрдбрд╝ рджреЗрддреЗ рд╣реИрдВред


рд╣рдо рдПрдХ рдлрд╝реИрдХреНрдЯрд░реА рд╡рд┐рдзрд┐ рд▓рд┐рдЦреЗрдВрдЧреЗ рдЬреЛ рд╕реВрдЪрдирд╛рдПрдВ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╕реЗ рдЕрдиреБрдореЛрджрди рдХреЗ рд▓рд┐рдП рдЕрдиреБрд░реЛрдз рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЪреИрдирд▓ рдмрдирд╛рдПрдЧреА:


 import { eventChannel, END } from 'redux-saga'; export function createRequestNotificationPermissionChannel() { const subscribe = emitter => { Notification.requestPermission(permission => { emitter(permission); emitter(END); }); return () => {}; }; return eventChannel(subscribe); } 

рдПрдХ рдЕрдиреНрдп рдХрд╛рд░рдЦрд╛рдиреЗ рд╡рд┐рдзрд┐ рдХреА рдЦреЛрдЬ рдореЗрдВ, рд▓реЗрдХрд┐рди рдПрдХ рдЕрдзрд┐рд╕реВрдЪрдирд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЪреИрдирд▓ рдХреЗ рд╕рд╛рде:


 import { eventChannel, END } from 'redux-saga'; export function createNotificationClickChannel(notification) { const subscribe = emitter => { notification.onclick = event => { emitter(event); emitter(END); }; return () => notification.onclick = null; }; return eventChannel(subscribe); } 

рджреЛрдиреЛрдВ рдЪреИрдирд▓ рдПрдХ рд╣реА рдХрд╛рд░реНрдпрдХреНрд░рдо рдореЗрдВ рдПрдХрд▓-рдЙрдкрдпреЛрдЧ рдФрд░ рдЕрдзрд┐рдХрддрдо рд╢реВрдЯрд┐рдВрдЧ рд╣реИрдВ, рдЬрд┐рд╕рдХреЗ рдмрд╛рдж рд╡реЗ рдмрдВрдж рд╣реЛ рдЬрд╛рддреЗ рд╣реИрдВред


рдХреБрдВрдЬреА рдмрдиреА рд╣реБрдИ рд╣реИ - рддрд░реНрдХ рдХреЗ рд╕рд╛рде рдЧрд╛рдерд╛ред рдЬрд╛рдВрдЪреЗрдВ рдХрд┐ рдХреНрдпрд╛ рдЯреИрдм рд╕рдХреНрд░рд┐рдп рд╣реИ, рдЕрдиреБрдорддрд┐ рдХрд╛ рдЕрдиреБрд░реЛрдз рдХрд░реЗрдВ, рдПрдХ рдЕрдзрд┐рд╕реВрдЪрдирд╛ рдмрдирд╛рдПрдВ, рдПрдХ рдХреНрд▓рд┐рдХ рдпрд╛ рдЯрд╛рдЗрдордЖрдЙрдЯ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░реЗрдВ, рдирдИ рд░рд┐рдХреНрддрд┐рдпреЛрдВ рдХреЛ рджрд┐рдЦрд╛рдПрдВ, рдЯреИрдм рдХреЛ рд╕рдХреНрд░рд┐рдп рдХрд░реЗрдВ рдФрд░ рдлрд┐рд░ рдЕрдзрд┐рд╕реВрдЪрдирд╛ рдХреЛ рдмрдВрдж рдХрд░реЗрдВ:


 import { delay } from 'redux-saga'; import { call, select, race, take } from 'redux-saga/effects'; import { createRequestNotificationPermissionChannel } from '../channels/request-notification-permission'; import { createNotificationClickChannel } from '../channels/notification-click'; import { JobsActions } from '../actions/jobs'; export function * notificationsSaga(action) { const { inFocus } = yield select(); if (inFocus) return; const permissionChannel = yield call(createRequestNotificationPermissionChannel); const permission = yield take(permissionChannel); if (permission !== 'granted') return; const notification = new Notification( `You have ${action.payload.jobs.length} new job posts`, { icon: 'assets/new-jobs.png' } ); const clickChannel = yield call(createNotificationClickChannel, notification); const { click, timeout } = yield race({ click: take(clickChannel), timeout: call(delay, 5000), }); if (click) { yield put(JobsActions.show()); window.focus(); window.scrollTo(0, 0); } notification.close(); } 

рдЗрд╕ рд╕реБрд╡рд┐рдзрд╛ рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдЧрд╛рдерд╛ рдХреЛ рдорд╛рдЙрдВрдЯ рдХрд░реЗрдВ:


 import { takeEvery } from 'redux-saga/effects'; import { JobsActions } from '../actions/jobs'; import { notificationsSaga } from './notifications'; export default function * sagas() { if ( 'Notification' in window && Notification.permission !== 'denied' ) { yield takeEvery(JobsActions.fresh, notificationsSaga); } } 

рдЧреНрд▓реЛрдмрд▓ рдЗрд╡реЗрдВрдЯ рдмрд╕


рдорд╛рдорд▓реЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ: Redux- рд╕реНрдЯреЛрд░ рдХреЗ рдмреАрдЪ рдШрдЯрдирд╛рдУрдВ рдХреА рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╢реНрд░реЗрдгреА рдХреЛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░реЗрдВ


рдпрджрд┐ рд╕рд╛рдорд╛рдиреНрдп рдбреЗрдЯрд╛ рд╡рд╛рд▓реЗ рдХрдИ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдкреГрд╖реНрда рдкрд░ рдореМрдЬреВрдж рд╣реИрдВ, рддреЛ рдРрд╕реА рдмрд╕ рдЖрд╡рд╢реНрдпрдХ рд╣реИред рдЗрд╕реА рд╕рдордп, рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЛ рдПрдХ-рджреВрд╕рд░реЗ рд╕реЗ рд╕реНрд╡рддрдВрддреНрд░ рд░реВрдк рд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред


рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдлрд╝рд┐рд▓реНрдЯрд░ рдХреЗ рд╕рд╛рде рдПрдХ рдЦреЛрдЬ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдФрд░ рдЕрд▓рдЧ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рд░реВрдк рдореЗрдВ рдЦреЛрдЬ рдкрд░рд┐рдгрд╛рдоред рдлрд╝рд┐рд▓реНрдЯрд░ рдмрджрд▓рддреЗ рд╕рдордп, рдореИрдВ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рдкрд░рд┐рдгрд╛рдо рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдкрд░ рднреА рд╣реИред


рд╣рдо рдорд╛рдирдХ рдЗрд╡реЗрдВрдЯ рдПрдорд┐рдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ:


 import EventEmmiter from 'events'; if (!window.GlobalEventBus) { window.GlobalEventBus = new EventEmmiter(); } export const globalEventBus = window.GlobalEventBus; 

рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдкреНрд░рд┐рдп рдШрдЯрдирд╛рдЪреИрдирд▓ рдПрдХ рдЪреИрдирд▓ рдореЗрдВ рдПрдХ рдорд╛рдирдХ рдПрдорд┐рдЯрд░ рдмрджрд▓ рдЬрд╛рддрд╛ рд╣реИ:


 import { eventChannel } from 'redux-saga'; import { globalEventBus as bus } from '../utils/global-event-bus'; exports function createGlobalEventBusChannel() { const subscribe = emitter => { const handler = event => emitter({ ...event, external: true }); bus.on('global.event', handler); return bus.removeListener('global.event', handler); }; return eventChannel(subscribe); } 

рдЧрд╛рдерд╛ рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИ - рд╣рдо рдПрдХ рдЪреИрдирд▓ рдмрдирд╛рддреЗ рд╣реИрдВ рдФрд░ рдШрдЯрдирд╛рдУрдВ рдХреЛ рдЖрдВрддрд░рд┐рдХ рдпрд╛ рдмрд╛рд╣рд░реА рд░реВрдк рд╕реЗ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддреЗ рд╣реИрдВред рдпрджрд┐ рд╣рдореЗрдВ рдХреЛрдИ рдЖрдВрддрд░рд┐рдХ рдШрдЯрдирд╛ рдкреНрд░рд╛рдкреНрдд рд╣реБрдИ рд╣реИ, рддреЛ рдЗрд╕реЗ рдмрд╕ рдореЗрдВ рднреЗрдЬреЗрдВ, рдпрджрд┐ рдмрд╛рд╣рд░реА рдПрдХ - рд╕реНрдЯреЛрд░ рдореЗрдВ:


 import { take, put, race, call } from 'redux-saga/effects'; import { globalEventBus as bus } from '../utils/global-event-bus'; import { createGlobalEventBusChannel } from '../channels/global-event-bus'; export function * globalEventBusSaga(allowedActions) { allowedActions = allowedActions.map(x => x.toString()); const channel = yield call(createGlobalEventBusChannel); while (true) { const { local, external } = yield race({ local: take(), external: take(channel), }); if ( external && allowedActions.some(action => action === external.type) ) { yield put(external); } if ( local && !local.external && allowedActions.some(action => action === local.type) ) { bus.emit('global.event', local); } } }; 

рдФрд░ рдЕрдВрддрд┐рдо рдПрдХ - рдЖрд╡рд╢реНрдпрдХ рдШрдЯрдирд╛рдУрдВ рдХреЗ рд╕рд╛рде рдЧрд╛рдерд╛ рдмрдврд╝рддреЗ:


 import { fork } from 'redux-saga/effects'; import { globalEventBusSaga } from './global-event-bus'; import { DropdownsActions } from '../actions/dropdowns'; import { AreasActions } from '../actions/areas'; export function * sagas() { yield fork(globalEventBusSaga, [ DropdownsActions.closeAll, AreasActions.add, AreasActions.remove, ... ]); } 



рдореБрдЭреЗ рдЖрд╢рд╛ рд╣реИ рдХрд┐ рдпрд╣ рджрд┐рдЦрд╛рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реИ рдХрд┐ рд╕рд╛рдЧрд╛ рдЬрдЯрд┐рд▓ рджреБрд╖реНрдкреНрд░рднрд╛рд╡реЛрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдирд╛ рдЖрд╕рд╛рди рдмрдирд╛рддреЗ рд╣реИрдВред рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдПрдкреАрдЖрдИ рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдПрдВ, рдЕрдкрдиреЗ рдорд╛рдорд▓реЛрдВ рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рдг рдХрд░реЗрдВ, рдШрдЯрдирд╛ рдХреА рдЕрдкреЗрдХреНрд╖рд╛ рдХреЗ рдЬрдЯрд┐рд▓ рдкреИрдЯрд░реНрди рдмрдирд╛рдПрдВ рдФрд░ рдЦреБрд╢ рд░рд╣реЗрдВред рдЬреЗрдПрд╕ рдЦреБрд▓реА рдЬрдЧрд╣реЛрдВ рдкрд░ рдорд┐рд▓рддреЗ рд╣реИрдВ!

Source: https://habr.com/ru/post/hi438856/


All Articles