"рдЖрдкрдХреЛ рдлрд╝реНрд▓рдХреНрд╕ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдиреЗ рдкрд░ рд╕рдордЭ рдЬрд╛рдПрдЧрд╛ред рдпрджрд┐ рдЖрдк рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдирд╣реАрдВ рд╣реИрдВ рдХрд┐ рдЖрдкрдХреЛ рдЗрд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рддреЛ рдЖрдкрдХреЛ рдЗрд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред" рдкреАрдЯ рд╢рд┐рдХрд╛рд░

рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рд╕реНрдерд┐рддрд┐ рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВ рдЖрдорддреМрд░ рдкрд░ Redux рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВред рд▓реЗрдХрд┐рди рд╣рдореЗрд╢рд╛ рдПрдХреНрд╢рди \ Reducer рдореЙрдбрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рдпрджрд┐ рдХреЗрд╡рд▓ рд╕рд░рд▓ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд╕рдХреЗ рдЖрд╡реЗрджрди рдХреА рд╢реНрд░рдорд╕рд╛рдзреНрдпрддрд╛ рдХреЗ рдХрд╛рд░рдгред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдХрд╛рдЙрдВрдЯрд░ рд▓реЗрдВред рдЖрдЙрдЯрдкреБрдЯ рдкрд░, рдореИрдВ рдПрдХ рд╕рд░рд▓ рдФрд░ рд╡реНрдпрд╛рд╡рд╣рд╛рд░рд┐рдХ рд╕рдорд╛рдзрд╛рди рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛ рдЬреЛ рд╣рдореЗрдВ рдПрдХ рд░рд╛рдЬреНрдп рдореЙрдбрд▓ рдФрд░ рдЗрд╕реЗ рдмрджрд▓рдиреЗ рд╡рд╛рд▓реЗ рдХреБрдЫ рддрд░реАрдХреЛрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдЬреИрд╕реЗ рдХрд┐:
state = {value: 0} increase() { state.value += 1 } decrease() { state.value -= 1 }
рдпрд╣ рддреБрд░рдВрдд рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ MobX рдЗрд╕ рддрд░рд╣ рдХрд╛ рд╕рдорд╛рдзрд╛рди рдкреНрд░рджрд╛рди рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рддреЛ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреНрдпреЛрдВ рди рдХрд░реЗрдВ? рдХреБрдЫ рд╕рдордп рдХреЗ рд▓рд┐рдП MobX рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рдореИрдВ рдЗрд╕ рдирддреАрдЬреЗ рдкрд░ рдкрд╣реБрдВрдЪрд╛ рдХрд┐ рдореЗрд░реЗ рд▓рд┐рдП рдПрдХ рдкрд░рд┐рд╡рд░реНрддрдирд╢реАрд▓ рдЕрд╡рд╕реНрдерд╛ (рдЬреИрд╕реЗ MobX) рдХреЗ рддрд░реНрдХ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рд╡реНрдпрдХреНрддрд┐рдЧрдд рд░реВрдк рд╕реЗ рдЕрдкрд░рд┐рд╡рд░реНрддрдиреАрдп рдЕрд╡рд╕реНрдерд╛рдУрдВ (рдЬреИрд╕реЗ Redux) рдХреЛ рд╕рдВрдЪрд╛рд▓рд┐рдд рдХрд░рдирд╛ рдЖрд╕рд╛рди рд╣реИ, рдФрд░ рдореИрдВ рдЕрдкрдиреА рдЖрдВрддрд░рд┐рдХ рд░рд╕реЛрдИ рдХреЛ рд╕рд░рд▓ рдирд╣реАрдВ рдХрд╣реВрдБрдЧрд╛ред
рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдореИрдВ рдЙрдиреНрдореБрдХреНрддрд┐ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рдПрдХ рд╕рд░рд▓ рд░рд╛рдЬреНрдп рдкреНрд░рдмрдВрдзрди рд╕рдорд╛рдзрд╛рди рдЦреЛрдЬрдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛, рдЗрд╕реЗ Angular \ React рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдХреЗ рд╕рд╛рде рдФрд░ рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдкрд░ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЧрдпрд╛ред рдЬреАрдердм рдЦреБрд▓реЗ рд╕реНрдерд╛рдиреЛрдВ рдкрд░ рдПрдХ рддреНрд╡рд░рд┐рдд рд╕рдореАрдХреНрд╖рд╛ рдиреЗ рдПрдХ рдЙрдкрдпреБрдХреНрдд рд╕рдорд╛рдзрд╛рди рдирд╣реАрдВ рджрд┐рдпрд╛, рдЗрд╕рд▓рд┐рдП рдЪрд▓реЛ RxJS / Immer рд▓реЗрдВ рдФрд░ рдЕрдкрдирд╛ рдЦреБрдж рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВред
рд╣рдо RxJS рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ
рд╣рдо BehaviorSubjet
рдХреЛ рдПрдХ рдЖрдзрд╛рд░ рдХреЗ рд░реВрдк рдореЗрдВ рд▓реЗрдВрдЧреЗ, рдЬреЛ рд░рд╛рдЬреНрдп рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЗ рдкреНрд░рд╡рд╛рд╣ рдХреЛ рдореЙрдбрд▓ рдХрд░реЗрдЧрд╛ {value: 0} -> {value: 1} -> {value: 2}
рдФрд░ рдЬрд┐рд╕рдореЗрдВ рдПрдХ getValue
рд╡рд┐рдзрд┐ рднреА рд╣реИ рдЬрд┐рд╕рдХреЗ рд╕рд╛рде рдЖрдк рд╡рд░реНрддрдорд╛рди рд╕реНрдерд┐рддрд┐ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдпрджрд┐ рдЖрдк Redux рдХреЗ рд╕рд╛рде BehaviorSubject
API рдХреА рддреБрд▓рдирд╛ рдХрд░рддреЗ рд╣реИрдВ
getValue() / getState() //
subscribe() / subscribe() //
next(value) / dispatch(action), replaceReducer(nextReducer) //
рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╡реЗ рдХрд╛рдлреА рд╕рдорд╛рди рд╣реИрдВред рдореБрдЦреНрдп рдЕрдВрддрд░ рдпрд╣ рд╣реИ рдХрд┐ BehaviorSubject
Action/Reducer
рдмрдЬрд╛рдп Action/Reducer
next()
рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдирдпрд╛ рд░рд╛рдЬреНрдп рд╕реЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рдЙрдкрд░реЛрдХреНрдд рдХрд╛рдЙрдВрдЯрд░ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЗрд╕ рддрд░рд╣ рджрд┐рдЦ рд╕рдХрддрд╛ рд╣реИ:
CounterService V1
class CounterServiceV1 { state = new BehaviorSubject({value: 0}) increase() { this.state.next({value: this.state.value.value + 1}) } decrease() { this.state.next({value: this.state.value.value - 1}) } }
рдЗрд╕ рд╕реЗ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдХреА this.state.next
рдФрд░ рд░рд╛рдЬреНрдп рдкрд░рд┐рд╡рд░реНрддрди рдХреА this.state.next
рд╣рдбрд╝рддрд╛рд▓реА рд╣реИрдВред рдпрд╣ рд╡рд╛рдВрдЫрд┐рдд рдкрд░рд┐рдгрд╛рдо рд╕реНрдерд┐рддрд┐ рд╕реЗ рдмрд╣реБрдд рдЕрд▓рдЧ рд╣реИред state.value += 1
Immer рдЬреЛрдбрд╝реЗрдВ
рдкреНрд░рддрд┐рд░рдХреНрд╖рд╛ рд╕реНрдерд┐рддрд┐ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдХреЛ рд╕рд░рд▓ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдЗрдореЗрд░ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рд╡рд░реНрддрдорд╛рди рдХреЗ рдЙрддреНрдкрд░рд┐рд╡рд░реНрддрди рдХреЗ рдХрд╛рд░рдг Immer рдЖрдкрдХреЛ рдПрдХ рдирдИ рдЕрдкрд░рд┐рд╡рд░реНрддрдиреАрдп рд╕реНрдерд┐рддрд┐ рдмрдирд╛рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдпрд╣ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ:
const state = {value: 0}
рд╡реНрдпрд╡рд╣рд╛рд░ рдФрд░ рд╡рд┐рд╖рдп рдХрд╛ рдмрдВрдбрд▓
рд╣рдорд╛рд░реА рд╣реА рдХрдХреНрд╖рд╛ рдореЗрдВ BehaviorSubject
рдФрд░ Immer рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ рдФрд░ рдЗрд╕реЗ RxState
:
class RxState<TState> { private subject$: BehaviorSubject<TState> private currentDraft?: Draft<TState> get state() { return this.subject$.value } get state$() { return this.subject$ } get draft(): Draft<TState> { if (this.currentDraft !== undefined) { return this.currentDraft } throw new Error("draft doesn't exists") } constructor(readonly initialState: TState) { this.subject$ = new BehaviorSubject(initialState) } public updateState(recipe: (draft: Draft<TState>) => void) { let topLevelUpdate = false
RxState
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ RxState
, рд╣рдо CounterService
RxState
рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрддреЗ рд╣реИрдВ:
рдХрд╛рдЙрдВрдЯрд░рд╕реЗрд╡рд╛ V2
class CounterServiceV2 { state = new RxState({value: 0}) increase() { this.state.updateState(draft => { draft.value += 1 }) } decrease() { this.state.updateState(draft => { draft.value -= 1 }) } }
diff - state = new BehaviorSubject({value: 0}) + state = new RxState({value: 0}) increase() { - this.state.next({value: this.state.value.value + 1}) + this.state.updateState(draft => { + draft.value += 1 + }) } decrease() { - this.state.next({value: this.state.value.value - 1}) + this.state.updateState(draft => { + draft.value -= 1 + }) }
рдпрд╣ рдкрд╣рд▓реЗ рд╡рд┐рдХрд▓реНрдк рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдереЛрдбрд╝рд╛ рдмреЗрд╣рддрд░ рджрд┐рдЦрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╣рд░ рдмрд╛рд░ updateState
рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдХ рдЕрдиреНрдп рд╡рд░реНрдЧ рдмрдирд╛рдПрдВ рдФрд░ рдЗрд╕реЗ SimpleImmutableStore
, рдпрд╣ рдХрд╣рд╛рдиреА рдХрд╛ рдЖрдзрд╛рд░ рд╣реЛрдЧрд╛ред
class SimpleImmutableStore<TState> { rxState!: RxState<TState> get draft() { return this.rxState.draft } constructor(initialState: TState) { this.rxState = new RxState<TState>(initialState) } public updateState(recipe: (draft: Draft<TState>) => void) { this.rxState.updateState(recipe) } }
рд╣рдо рдЗрд╕рдХреА рдорджрдж рд╕реЗ рд╕реНрдЯреЛрд░ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВ:
рдХрд╛рдЙрдВрдЯрд░рд╕реНрдЯреЛрд░ V1
class CounterStoreV1 extends SimpleImmutableStore<{value: number}> { constructor(){ super({value: 0}) } increase() { this.updateState(() => { this.draft.value += 1 }) } decrease() { this.updateState(() => { this.draft.value -= 1 }) } }
diff -class CounterServiceV2 { - state = new RxState({value: 0}) +class CounterStoreV1 extends SimpleImmutableStore<{value: number}> { + constructor(){ + super({value: 0}) + } increase() { - this.state.updateState(draft => { - draft.value += 1 + this.updateState(() => { + this.draft.value += 1 }) } decrease() { - this.state.updateState(draft => { - draft.value -= 1 + this.updateState(() => { + this.draft.value -= 1 }) } }
рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдХреБрдЫ рднреА рдорд╣рддреНрд╡рдкреВрд░реНрдг рд░реВрдк рд╕реЗ рдирд╣реАрдВ рдмрджрд▓рд╛ рдЧрдпрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдм рд╕рднреА рддрд░реАрдХреЛрдВ рдореЗрдВ рдПрдХ рдЖрд╡рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рд╕рдорд╛рди рдХреЛрдб рд╣реИ this.updateState
ред рдЗрд╕ рджреЛрд╣рд░рд╛рд╡ рд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдПрдХ рдлрд╝рдВрдХреНрд╢рди рд▓рд┐рдЦрддреЗ рд╣реИрдВ рдЬреЛ рдПрдХ updateState
рдХреЙрд▓ рдореЗрдВ рд╕рднреА рд╡рд░реНрдЧ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рд▓рдкреЗрдЯрддрд╛ рд╣реИ:
const wrapped = Symbol()
рдФрд░ рд╣рдо рдЗрд╕реЗ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдореЗрдВ рдХрд╣реЗрдВрдЧреЗ (рдпрджрд┐ рд╡рд╛рдВрдЫрд┐рдд рд╣реИ, рддреЛ рдпрд╣ рд╡рд┐рдзрд┐ рдХреНрд▓рд╛рд╕ рдХреЗ рд▓рд┐рдП рдбреЗрдХреЛрд░реЗрдЯрд░ рдХреЗ рд░реВрдк рдореЗрдВ рднреА рд▓рд╛рдЧреВ рдХреА рдЬрд╛ рд╕рдХрддреА рд╣реИ)
constructor(initialState: TState ) { this.rxState = new RxState<TState>(initialState) wrapMethodsWithUpdateState(this.constructor) }
CounterStore
рдХрд╣рд╛рдиреА рдХрд╛ рдЕрдВрддрд┐рдо рд╕рдВрд╕реНрдХрд░рдгред рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдХ рдЫреЛрдЯреЗ рддрд░реНрдХ рдХреЛ decrease
рдФрд░ рдПрдХ рдЬреЛрдбрд╝реЗ рдХреЛ рдФрд░ рдЕрдзрд┐рдХ рддрд░реАрдХреЛрдВ рдХреЗ рд╕рд╛рде setValue
рдкреИрд░рд╛рдореАрдЯрд░ рдкрд╛рд╕ рдХрд░рдирд╛ рдФрд░ setValue
рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ setValue
:
class CounterStore extends SimpleImmutableStore<{ value: number }> { constructor() { super({value: 0}) } increase() { this.draft.value += 1 } decrease() { const newValue = this.draft.value - 1 if (newValue >= 0) { this.draft.value = newValue } } setValue(value: number) { this.draft.value = value } increaseWithDelay() { setTimeout(() => this.increase(), 300) } }
рдХреЛрдгреАрдп рдХреЗ рд╕рд╛рде рдкреНрд░рдпреЛрдЧ рдХрд░реЗрдВ
рдЪреВрдВрдХрд┐ RxJS рдкрд░рд┐рдгрд╛рдореА рд╕реНрдЯреИрдХ рдХрд╛ рдЖрдзрд╛рд░ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдПрдВрдЧреБрд▓рд░ рдХреЗ рд╕рд╛рде async
рдкрд╛рдЗрдк рдХреЗ рд╕рд╛рде рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:
<div *ngIf="store.rxState.state$ | async as state"> <span>{{state.value}}</span> <button (click)="store.increase()">+</button> <button (click)="store.decrease()">-</button> <button (click)="store.setValue(0)">Reset</button> <button (click)="store.increaseWithDelay()">Increase with delay</button> </div>
рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рд╕рд╛рде рдкреНрд░рдпреЛрдЧ рдХрд░реЗрдВ
рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рд▓рд┐рдП, рд╣рдо рдПрдХ рдХрд╕реНрдЯрдо рд╣реБрдХ рд▓рд┐рдЦреЗрдВрдЧреЗ:
function useStore<TState, TResult>( store: SimpleImmutableStore<TState>, project: (store: TState) => TResult, ): TResult { const projectRef = useRef(project) useEffect(() => { projectRef.current = project }, [project]) const [state, setState] = useState(projectRef.current(store.rxState.state)) useEffect(() => { const subscription = store.rxState.state$.subscribe(value => { const newState = projectRef.current(value) if (!shallowEqual(state, newState)) { setState(newState) } }) return () => { subscription.unsubscribe() } }, [store, state]) return state }
рдЕрдВрдЧ
const Counter = () => { const store = useMemo(() => new CounterStore(), []) const value = useStore(store, x => x.value) return ( <div className="counter"> <span>{value}</span> <button onClick={() => store.increase()}>+</button> <button onClick={() => store.decrease()}>-</button> <button onClick={() => store.setValue(0)}>Reset</button> <button onClick={() => store.increaseWithDelay()}>Increase with delay</button> </div> ) }
рдирд┐рд╖реНрдХрд░реНрд╖
рдкрд░рд┐рдгрд╛рдо рдПрдХ рдХрд╛рдлреА рд╕рд░рд▓ рдФрд░ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рд╕рдорд╛рдзрд╛рди рд╣реИ, рдЬрд┐рд╕рдХрд╛ рдореИрдВ рд╕рдордп-рд╕рдордп рдкрд░ рдЕрдкрдиреА рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВред рдпрджрд┐ рдЖрдк рдЪрд╛рд╣реЗрдВ, рддреЛ рдЖрдк рдЗрд╕ рддрд░рдл рд╡рд┐рднрд┐рдиреНрди рдЙрдкрдпреЛрдЧрд┐рддрд╛рдПрдБ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ: рдорд┐рдбрд▓рд╡реЗрдпрд░, рд╕реНрдЯреЗрдЯ рд╕реНрд▓рд╛рдЗрд╕рд┐рдВрдЧ, рдЕрдкрдбреЗрдЯрдмреИрдХрдмреИрдХ - рд▓реЗрдХрд┐рди рдпрд╣ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЗрд╕ рд▓реЗрдЦ рдХреЗ рджрд╛рдпрд░реЗ рд╕реЗ рдкрд░реЗ рд╣реИред рдЗрд╕ рддрд░рд╣ рдХреЗ рдкрд░рд┐рд╡рд░реНрдзрди рдХрд╛ рдкрд░рд┐рдгрд╛рдо github https://github.com/simmor-store/simmor рдкрд░ рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ
рдореИрдВ рдХрд┐рд╕реА рднреА рд╕реБрдЭрд╛рд╡ рдФрд░ рдЯрд┐рдкреНрдкрдгреА рдХреЗ рд▓рд┐рдП рдЖрднрд╛рд░реА рд░рд╣реВрдВрдЧрд╛ред