#Introduction
ReactorKit is a framework for a reactive and unidirectional Swift application architecture. ReactorKit is a combination of Flux and Reactive Programming. The user actions and the view states are delivered to each layer via observable streams. These streams are unidirectional so the view can only emit actions and the reactor can only emit states.
#Architecture
A View displays data. A view controller and a cell are treated as a view. The view binds user inputs to the action stream and binds the view states to each UI component. There's no business logic in a view layer. A view just defines how to map the action stream and the state stream.
A Reactor is an UI-independent layer which manages the state of a view. The foremost role of a reactor is to separate control flow from a view. Every view has its corresponding reactor and delegates all logic to its reactor. A reactor has no dependency to a view, so it can be easily tested. Conform to the Reactor protocol to define a reactor. This protocol requires three types to be defined: Action, Mutation and State. It also requires a property named initialState.
Action represents a user interaction and State represents a view state. Mutation is a bridge between Action and State. A reactor converts the action stream to the state stream in two steps: mutate() and reduce().
mutate() receives an Action and generates an Observable
func mutate(action: Action) -> Observable<Mutation>
reduce() generates a new State from a previous State and a Mutation.
func reduce(state: State, mutation: Mutation) -> State
This method is a pure function. It should just return a new State synchronously. Don't perform any side effects in this function.
func reduce(state: State, mutation: Mutation) -> State {
var state = state // create a copy of the old state
switch mutation {
case let .setFollowing(isFollowing):
state.isFollowing = isFollowing // manipulate the state, creating a new state
return state // return the new state
}
}
Implement these methods to transform and combine with other observable streams. For example, transform(mutation:) is the best place for combining a global event stream to a mutation stream.
class ProfileViewReactor: Reactor {
// represent user actions
enum Action {
case refreshFollowingStatus(Int)
case follow(Int)
}
// represent state changes
enum Mutation {
case setFollowing(Bool)
}
// represents the current view state
struct State {
var isFollowing: Bool = false
}
let initialState: State = State()
}
#Sample Login Validation with ReactorKit
Simple login form with validation and using ReactorKit. So I validate the User Name input by entering 7 characters or more. Same as password, I validate need to add Capital letter, special character, number, together more than 7. if user not input as the condition so it displays error message like the above image.
Sample Code here in github