
рдЗрд╕ рд╕рдкреНрддрд╛рд╣ рд╣рдо
Redux рджреНрд╡рд╛рд░рд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЧрдП рдПрдХ рдХреЗ рд╕рдорд╛рди рдПрдХ рд░рд╛рдЬреНрдп рдХрдВрдЯреЗрдирд░ рдмрдирд╛рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░реЗрдВрдЧреЗред рдпрд╣ рд╡рд┐рдХрд╛рд╕ рдХреЗ рддрд╣рдд рдЖрд╡реЗрджрди рдХреЗ рд▓рд┐рдП рдореВрд▓реНрдп рдХрд╛ рдПрдХрдорд╛рддреНрд░ рд╕реНрд░реЛрдд рд╣реИред рдкреВрд░реЗ рдЖрд╡реЗрджрди рдХреЗ рд▓рд┐рдП рдПрдХ рдПрдХрд▓ рд░рд╛рдЬреНрдп рдбрд┐рдмрдЧрд┐рдВрдЧ рдФрд░ рд╕рддреНрдпрд╛рдкрди рдХреЛ рдЖрд╕рд╛рди рдмрдирд╛рддрд╛ рд╣реИред рд╕рддреНрдп рдореВрд▓реНрдпреЛрдВ рдХрд╛ рдПрдХ рдПрдХрд▓ рд╕реНрд░реЛрдд рд╣рдЬрд╛рд░реЛрдВ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рд╕рдорд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдПрдХ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдореЗрдВ рдХрдИ рд░рд╛рдЬреНрдпреЛрдВ рдХреЛ рдмрдирд╛рддреЗ рд╕рдордп рд╣реЛрддрд╛ рд╣реИред
рд╕рддреНрдп рдореВрд▓реНрдпреЛрдВ рдХрд╛ рдПрдХрд▓ рд╕реНрд░реЛрдд
рдореБрдЦреНрдп рд╡рд┐рдЪрд╛рд░ рдПрдХрд▓ рд╕рдВрд░рдЪрдирд╛ рдпрд╛ рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХреА рд╕рдВрд░рдЪрдирд╛ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкреВрд░реЗ рдЖрд╡реЗрджрди рдХреА рд╕реНрдерд┐рддрд┐ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдирд╛ рд╣реИред рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рд╣рдо рдПрдХ рдЬреАрдердм рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдЦреЛрдЬ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдкрд░ рдХрд╛рдо рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдЬрд╣рд╛рдВ рд░рд╛рдЬреНрдп рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреА рдПрдХ рд╕рд░рдгреА рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рдЬреАрдердм рдПрдкреАрдЖрдИ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЕрдиреБрд░реЛрдз рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдЪреБрдирддреЗ рд╣реИрдВред
struct AppState { var searchResult: [Repo] = [] }
рдЕрдЧрд▓рд╛ рдХрджрдо рдЖрд╡реЗрджрди рдХреЗ рднреАрддрд░ рдкреНрд░рддреНрдпреЗрдХ рджреГрд╢реНрдп рдХреЗ рд▓рд┐рдП рд░рд╛рдЬреНрдп (рдХреЗрд╡рд▓ рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП) рдХреЛ рдкрд╛рд░рд┐рдд рдХрд░рдирд╛ рд╣реИред рдЗрд╕реЗ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХрд╛ рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рддрд░реАрдХрд╛ рд╕реНрд╡рд┐рдлреНрдЯрдпреВрдЖрдИ рдХреЗ рдкрд░реНрдпрд╛рд╡рд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реИред рдЖрдк рдЖрдзрд╛рд░ рджреГрд╢реНрдп рдХреЗ рдкрд░реНрдпрд╛рд╡рд░рдг рдХреЗ рд▓рд┐рдП рд╕рдВрдкреВрд░реНрдг рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рд╕реНрдерд┐рддрд┐ рд╡рд╛рд▓реЗ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рднреА рдкрд╛рд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдмреЗрд╕ рджреГрд╢реНрдп рд╕рднреА рдмрдЪреНрдЪреЗ рдХреЗ рд╡рд┐рдЪрд╛рд░реЛрдВ рдХреЗ рд╕рд╛рде рдкрд░реНрдпрд╛рд╡рд░рдг рд╕рд╛рдЭрд╛ рдХрд░реЗрдВрдЧреЗред SwiftUI рдХреЗ рдкрд░реНрдпрд╛рд╡рд░рдг рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП,
SwiftUI рдкреНрд░рдХрд╛рд╢рди рдореЗрдВ рдкрд░реНрдпрд╛рд╡рд░рдг рдХреА
рд╢рдХреНрддрд┐ рдХреА рдЬрд╛рдБрдЪ рдХрд░реЗрдВред
final class Store: ObservableObject { @Published private(set) var state: AppState }
рдЙрдкрд░реЛрдХреНрдд рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рд╣рдордиреЗ рдПрдХ
рд╕реНрдЯреЛрд░ рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛рдпрд╛, рдЬреЛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рд╕реНрдерд┐рддрд┐ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рдХреЗрд╡рд▓ рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХреНрд╕реЗрд╕ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рд╕реНрдЯреЗрдЯ рдкреНрд░реЙрдкрд░реНрдЯреА
@Published рдкреНрд░реЙрдкрд░реНрдЯреА рдХреЗ рд░реИрдкрд░ рдХрд╛
рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд░рддреА рд╣реИ, рдЬреЛ рдХрд┐рд╕реА рднреА рдмрджрд▓рд╛рд╡ рдХреЗ SwiftUI рдХреЛ рд╕реВрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИред рдпрд╣ рдЖрдкрдХреЛ рдкреВрд░реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рд▓рдЧрд╛рддрд╛рд░ рдЕрдкрдбреЗрдЯ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдЗрд╕реЗ рд╕рддреНрдп рдореВрд▓реНрдпреЛрдВ рдХреЗ рдПрдХрд▓ рд╕реНрд░реЛрдд рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИред рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ, рд╣рдордиреЗ рдкрд┐рдЫрд▓реЗ рд▓реЗрдЦреЛрдВ рдореЗрдВ рд╕реНрдЯреЛрд░реЗрдЬ рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХреА рдереАред рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдФрд░ рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ "
рд╕реНрд╡рд┐рдлреНрдЯрдпреВрдЖрдИ рдореЗрдВ рд╕реНрдЯреЛрд░рд┐рдВрдЧ рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдореЙрдбрд▓рд┐рдВрдЧ рдПрдкреНрд▓реАрдХреЗрд╢рди рд╕реНрдЯреЗрдЯ "
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ ред
Reducer рдФрд░ рдХреНрд░рд┐рдпрд╛рдПрдБ
рдпрд╣ рдЙрди рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░рдиреЗ рдХрд╛ рд╕рдордп рд╣реИ рдЬреЛ рд░рд╛рдЬреНрдп рдкрд░рд┐рд╡рд░реНрддрди рдХрд╛ рдиреЗрддреГрддреНрд╡ рдХрд░рддреЗ рд╣реИрдВред рдПрдХ рдХреНрд░рд┐рдпрд╛ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдЧрдгрдирд╛ рдпрд╛ рдПрдХ рд░рд╛рдЬреНрдп рдкрд░рд┐рд╡рд░реНрддрди рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдЧрдгрдирд╛ рдХрд╛ рд╕рдВрдЧреНрд░рд╣ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдбреЗрдЯрд╛ рд╕реИрдВрдкрд▓рд┐рдВрдЧ рдХреЗ рджреМрд░рд╛рди рд▓реЛрдб рдорд╛рди рд╕реЗрдЯ рдХрд░реЗрдВ, рдкрд░рд┐рдгрд╛рдореА рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреЛ рдПрдХ рд░рд╛рдЬреНрдп рд╕рдВрдкрддреНрддрд┐, рдЖрджрд┐ рдХреЛ рдЕрд╕рд╛рдЗрди рдХрд░реЗрдВред рдЕрдм рдХрд╛рд░реНрд░рд╡рд╛рдИ рдХреА рдЧрдгрдирд╛ рдХреЗ рд▓рд┐рдП рдирдореВрдирд╛ рдХреЛрдб рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВред
enum AppAction { case search(query: String) case setSearchResult(repos: [Repo]) }
Reducer рдПрдХ рдлрд╝рдВрдХреНрд╢рди рд╣реИ рдЬреЛ рд╡рд░реНрддрдорд╛рди рд╕реНрдерд┐рддрд┐ рд▓реЗрддрд╛ рд╣реИ, рд░рд╛рдЬреНрдп рдкрд░ рдПрдХ рдХрд╛рд░реНрд░рд╡рд╛рдИ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдПрдХ рдирдпрд╛ рд░рд╛рдЬреНрдп рдмрдирд╛рддрд╛ рд╣реИред рдЖрдорддреМрд░ рдкрд░
рд░рд┐рдбреНрдпреВрд╕рд░ рдХреА рд░реАрдбреНрдпреВрд╕рд░ рдпрд╛
рд░рдЪрдирд╛ рдПрдХ рдРрд╕реА рдЬрдЧрд╣ рд╣реЛрддреА рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рдЖрд╡реЗрджрди рдмрджрд▓ рдЬрд╛рддрд╛ рд╣реИред рддрдереНрдп рдпрд╣ рд╣реИ рдХрд┐ рдПрдХ рдПрдХрд▓ рдлрд╝рдВрдХреНрд╢рди рдХрд┐рд╕реА рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рд╕рдВрдкреВрд░реНрдг рд╕реНрдерд┐рддрд┐ рдХреЛ рдмрджрд▓ рд╕рдХрддрд╛ рд╣реИ, рдХреЛрдб рдХреЛ рдмрд╣реБрдд рд╕рд░рд▓, рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдореЗрдВ рдЖрд╕рд╛рди рдФрд░ рдбреАрдмрдЧ рдХрд░рдирд╛ рдЖрд╕рд╛рди рдмрдирд╛рддрд╛ рд╣реИред рдирд┐рдореНрди рдХрд╛рд░реНрдп рдХреЛ рдХрдо рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИред
struct Reducer<State, Action> { let reduce: (inout State, Action) -> Void } let appReducer: Reducer<AppState, AppAction> = Reducer { state, action in switch action { case let .setSearchResults(repos): state.searchResult = repos } }
рдЕрдкреНрд░рддреНрдпрдХреНрд╖ рдкреНрд░рд╡рд╛рд╣
рдЕрдм рдбреЗрдЯрд╛ рдкреНрд░рд╡рд╛рд╣ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░рдиреЗ рдХрд╛ рд╕рдордп рд╣реИред рдкреНрд░рддреНрдпреЗрдХ рджреГрд╢реНрдп рдореЗрдВ рд╕реНрдЯреЛрд░ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд░рд╛рдЬреНрдп рдореЗрдВ рдХреЗрд╡рд▓ рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╣реБрдВрдЪ рд╣реИред рд╡реНрдпреВрдЬрд╝ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдСрдмреНрдЬреЗрдХреНрдЯ рдкрд░ рдХрд╛рд░реНрд░рд╡рд╛рдИ рднреЗрдЬ рд╕рдХрддреЗ рд╣реИрдВред Reducer рд░рд╛рдЬреНрдп рдмрджрд▓рддрд╛ рд╣реИ, рдФрд░ рдлрд┐рд░ SwiftUI рд░рд╛рдЬреНрдп рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЗ рд╕рднреА рд╡рд┐рдЪрд╛рд░реЛрдВ рдХреЛ рд╕реВрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИред SwiftUI рдореЗрдВ рдПрдХ рд╕реБрдкрд░-рдХреБрд╢рд▓ рддреБрд▓рдирд╛ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рд╣реИ, рдЗрд╕рд▓рд┐рдП рдкреВрд░реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рд╕реНрдерд┐рддрд┐ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдирд╛ рдФрд░ рдмрджрд▓реЗ рд╣реБрдП рд╡рд┐рдЪрд╛рд░реЛрдВ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдирд╛ рдмрд╣реБрдд рддреЗрдЬрд╝ рд╣реИред
рд░рд╛рдЬреНрдп -> тАЛтАЛрджреГрд╢реНрдп -> тАЛтАЛрдХреНрд░рд┐рдпрд╛ -> рд░рд╛рдЬреНрдп -> тАЛтАЛрджреГрд╢реНрдпрдпрд╣ рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдХреЗрд╡рд▓ рдПрдХ рдпреВрдирд┐рдбрд╛рдпрд░реЗрдХреНрд╢рдирд▓ рдбреЗрдЯрд╛ рд╕реНрдЯреНрд░реАрдо рдХреЗ рдЖрд╕рдкрд╛рд╕ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдЗрд╕рдХрд╛ рдорддрд▓рдм рдпрд╣ рд╣реИ рдХрд┐ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд╕рднреА рдбреЗрдЯрд╛ рдПрдХ рд╣реА рдкреИрдЯрд░реНрди рдХрд╛ рдЕрдиреБрд╕рд░рдг рдХрд░рддреЗ рд╣реИрдВ, рдЬреЛ рдмрдирд╛рдП рдЧрдП рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рддрд░реНрдХ рдХреЛ рдЕрдзрд┐рдХ рдкреВрд░реНрд╡рд╛рдиреБрдорд╛рди рдФрд░ рд╕рдордЭрдиреЗ рдореЗрдВ рдЖрд╕рд╛рди рдмрдирд╛рддрд╛ рд╣реИред рдХрд╛рд░реНрд░рд╡рд╛рдИ рд╕рдмрдорд┐рдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрдЯреЛрд░ рдСрдмреНрдЬреЗрдХреНрдЯ рдмрджрд▓реЗрдВред
final class Store<State, Action>: ObservableObject { @Published private(set) var state: State private let appReducer: Reducer<State, Action> init(initialState: State, appReducer: @escaping Reducer<State, Action>) { self.state = initialState self.appReducer = appReducer } func send(_ action: Action) { appReducer.reduce(&state, action) } }
рд╕рд╛рдЗрдб рдЗрдлреЗрдХреНрдЯ
рд╣рдордиреЗ рдкрд╣рд▓реЗ рд╣реА рдПрдХ
рдпреВрдирд┐рдбрд╛рдпрд░реЗрдХреНрд╢рдирд▓ рд╕реНрдЯреНрд░реАрдо рд▓рд╛рдЧреВ рдХрд░ рджрд┐рдпрд╛ рд╣реИ рдЬреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ рдФрд░ рд░рд╛рдЬреНрдп рдХреЛ рдмрджрд▓рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдПрдХ рдПрд╕рд┐рдВрдХреНрд╕ рдПрдХреНрд╢рди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреНрдпрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рд╣рдо рдЖрдорддреМрд░ рдкрд░
рд╕рд╛рдЗрдб рдЗрдлреЗрдХреНрдЯ рдХрд░рддреЗ рд╣реИрдВ ред рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЧрдП рд╕рдВрдЧреНрд░рд╣рдг рдкреНрд░рдХрд╛рд░ рдХреЗ рд▓рд┐рдП рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдХрд╛рд░реНрдп рд╕рдорд░реНрдерди рдХреИрд╕реЗ рдЬреЛрдбрд╝реЗрдВ? рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣
рд╕рдВрдпреЛрдЬрди рдлреНрд░реЗрдорд╡рд░реНрдХ рдХреЗ рдЙрдкрдпреЛрдЧ рдХреЛ рд╢реБрд░реВ рдХрд░рдиреЗ рдХрд╛ рд╕рдордп рд╣реИ, рдЬреЛ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд╕рдВрднрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрджрд░реНрд╢ рд╣реИред
import Foundation import Combine protocol Effect { associatedtype Action func mapToAction() -> AnyPublisher<Action, Never> } enum SideEffect: Effect { case search(query: String) func mapToAction() -> AnyPublisher<Action, Never> { switch self { case let .search(query): return dependencies.githubService .searchPublisher(matching: query) .replaceError(with: []) .map { AppAction.setSearchResults(repos: $0) } .eraseToAnyPublisher() } } }
рд╣рдордиреЗ рдкреНрд░рднрд╛рд╡ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЛ рд╢реБрд░реВ рдХрд░рдХреЗ
async рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди рдЬреЛрдбрд╝рд╛ред
рдкреНрд░рднрд╛рд╡ рдПрдХ рдПрдХреНрд╢рди рд╕реАрдХреНрд╡реЗрдВрд╕ рд╣реИ
, рдЬрд┐рд╕реЗ рдХреЙрдореНрдмрд┐рдиреЗрд╢рди рдлреНрд░реЗрдорд╡рд░реНрдХ рд╕реЗ рдкреНрд░рдХрд╛рд╢рдХ рдкреНрд░рдХрд╛рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреНрд░рдХрд╛рд╢рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдпрд╣ рдЖрдкрдХреЛ рдХрдореНрдмрд╛рдЗрди рдХреЗ рд╕рд╛рде рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдиреМрдХрд░рд┐рдпреЛрдВ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдФрд░ рдлрд┐рд░ рдЙрди рдХрд╛рд░реНрд░рд╡рд╛рдЗрдпреЛрдВ рдХреЛ рдкреНрд░рдХрд╛рд╢рд┐рдд рдХрд░рддрд╛ рд╣реИ рдЬреЛ Reducer рд╡рд░реНрддрдорд╛рди рд╕реНрдерд┐рддрд┐ рдкрд░ рдХрд╛рд░реНрд░рд╡рд╛рдИ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд░реЗрдЧрд╛ред
final class Store<State, Action>: ObservableObject { @Published private(set) var state: State private let appReducer: Reducer<State, Action> private var cancellables: Set<AnyCancellable> = [] init(initialState: State, appReducer: Reducer<State, Action>) { self.state = initialState self.appReducer = appReducer } func send(_ action: Action) { appReducer.reduce(&state, action) } func send<E: Effect>(_ effect: E) where E.Action == Action { effect .mapToAction() .receive(on: DispatchQueue.main) .sink(receiveValue: send) .store(in: &cancellables) } }
рд╡реНрдпрд╛рд╡рд╣рд╛рд░рд┐рдХ рдЙрджрд╛рд╣рд░рдг
рдЕрдВрдд рдореЗрдВ, рд╣рдо рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдЦреЛрдЬ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдкреВрд░рд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЬреЛ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд░реВрдк рд╕реЗ
рдЧрд┐рдердм рдПрдкреАрдЖрдИ рдХреЛ рдХреЙрд▓ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдХреНрд╡реЗрд░реА рд╕реЗ рдореЗрд▓ рдЦрд╛рдиреЗ рд╡рд╛рд▓реЗ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХрд╛ рдЪрдпрди рдХрд░рддрд╛ рд╣реИред рдЖрд╡реЗрджрди рдХрд╛ рдкреВрд░реНрдг рд╕реНрд░реЛрдд рдХреЛрдб
рдЬреАрдердм рдкрд░ рдЙрдкрд▓рдмреНрдз рд╣реИред
struct SearchContainerView: View { @EnvironmentObject var store: Store<AppState, AppAction> @State private var query: String = "Swift" var body: some View { SearchView( query: $query, repos: store.state.searchResult, onCommit: fetch ).onAppear(perform: fetch) } private func fetch() { store.send(SideEffect.search(query: query)) } } struct SearchView : View { @Binding var query: String let repos: [Repo] let onCommit: () -> Void var body: some View { NavigationView { List { TextField("Type something", text: $query, onCommit: onCommit) if repos.isEmpty { Text("Loading...") } else { ForEach(repos) { repo in RepoRow(repo: repo) } } }.navigationBarTitle(Text("Search")) } } }
рд╕реНрдХреНрд░реАрди рдХреЛ рджреЛ рджреГрд╢реНрдпреЛрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░реЗрдВ:
рдХрдВрдЯреЗрдирд░ рд╡реНрдпреВ рдФрд░
рд░реЗрдВрдбрд░рд┐рдВрдЧ рд╡реНрдпреВ ред
рдХрдВрдЯреЗрдирд░ рд╡реНрдпреВ рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рддрд╛ рд╣реИ рдФрд░
рд╡реИрд╢реНрд╡рд┐рдХ рд░рд╛рдЬреНрдп рд╕реЗ рдЖрд╡рд╢реНрдпрдХ рднрд╛рдЧреЛрдВ рдХрд╛ рдЪрдпрди рдХрд░рддрд╛ рд╣реИред
рд░реЗрдВрдбрд░рд┐рдВрдЧ рджреГрд╢реНрдп рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИред рд╣рдордиреЗ рдкрд┐рдЫрд▓реЗ рд▓реЗрдЦреЛрдВ рдореЗрдВ рдХрдВрдЯреЗрдирд░ рджреГрд╢реНрдпреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдмрд╛рдд рдХреА рд╣реИ, рдЕрдзрд┐рдХ рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП, рд▓рд┐рдВрдХ рдХрд╛ рдЕрдиреБрд╕рд░рдг рдХрд░реЗрдВ "
рд╕реНрд╡рд┐рдлреНрдЯрдпреВрдЖрдИ рдореЗрдВ рдХрдВрдЯреЗрдирд░ рд╡рд┐рдЪрд╛рд░реЛрдВ рдХрд╛ рдкрд░рд┐рдЪрдп "
рдирд┐рд╖реНрдХрд░реНрд╖
рдЖрдЬ рд╣рдордиреЗ рд╕реАрдЦрд╛ рдХрд┐
рд╕рд╛рдЗрдб-рдЗрдлреЗрдХреНрдЯ рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрддреЗ рд╣реБрдП Redux рдЬреИрд╕рд╛ рд╕реНрдЯреЗрдЯ рдХрдВрдЯреЗрдирд░ рдХреИрд╕реЗ рдмрдирд╛рдпрд╛
рдЬрд╛рдП ред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдордиреЗ рд╕реНрд╡рд┐рдлреНрдЯрдпреВрдЖрдИ рдкрд░реНрдпрд╛рд╡рд░рдг рдлрд╝рдВрдХреНрд╢рди рдФрд░ рдХрдВрдмрд╛рдЗрди рдврд╛рдВрдЪреЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ред рдореБрдЭреЗ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдпрд╣ рд▓реЗрдЦ рд╕рд╣рд╛рдпрдХ рд░рд╣рд╛ рд╣реИред
рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рдФрд░ рдЬрд▓реНрдж рд╣реА рдорд┐рд▓рддреЗ рд╣реИрдВ!