我们重新走下流程 😄,用 纯函数 做状态管理:
typealias UserID = String
enum LoginError: Error, Equatable {
case usernamePasswordMismatch
case offline
}
//首先,我们得有个状态
struct State: Equatable {
var username: String // 输入的用户名
var password: String // 输入的密码
var loading: Bool // 登录中
var data: UserID? // 登录成功
var error: LoginError? // 登录失败
//然后,我们要有各种事件
enum Event {
case onUpateUsername(String)
case onUpatePassword(String)
case onTriggerLogin
case onLoginSuccess(UserID)
case onLoginError(LoginError)
}
//最后,我们要有一个 纯函数 来管理我们的状态
static func reduce(_ state: State, event: Event) -> State {
var newState = state
switch event {
case .onUpateUsername(let username):
newState.username = username
case .onUpatePassword(let password):
newState.password = password
case .onTriggerLogin:
newState.loading = true
newState.data = nil
newState.error = nil
case .onLoginSuccess(let userId):
newState.loading = false
newState.data = userId
case .onLoginError(let error):
newState.loading = false
newState.error = error
}
return newState
}
}
现在我们可以在测试环境模拟各种事件,并且判断结果是否符合预期:
//更新用户名事件
func testOnUpateUsername() {
let state = State(username: "",password: "",loading: false,data: nil,error: nil)
let newState = State.reduce(state, event: .onUpateUsername("beeth0ven"))
let expect = State(username: "beeth0ven",password: "",loading: false,data: nil,error: nil)
newState == expect // 结果:true 😎
}
//更新密码事件
func testOnUpatePassword() {
let state = State(username: "beeth0ven",password: "",loading: false,data: nil,error: nil)
let newState = State.reduce(state, event: .onUpatePassword("123456"))
let expect = State(username: "beeth0ven",password: "123456",loading: false,data: nil,error: nil)
newState == expect // 结果:true 😎
}
//触发登录事件
func testOnTriggerLogin() {
let state = State(username: "beeth0ven",password: "123456",loading: false,data: nil,error: nil)
let newState = State.reduce(state, event: .onTriggerLogin)
let expect = State(username: "beeth0ven",password: "123456",loading: true,data: nil,error: nil)
newState == expect // 结果:true 😎
}
//登录成功事件
func testOnLoginSuccess() {
let state = State(username: "beeth0ven",password: "123456",loading: true,data: nil,error: nil)
let newState = State.reduce(state, event: .onLoginSuccess("userID007"))
let expect = State(username: "beeth0ven",password: "123456",loading: false,data: "userID007",error: nil)
newState == expect // 结果:true 😎
}
//登录失败事件
func testOnLoginError() {
let state = State(username: "beeth0ven",password: "123456",loading: true,data: nil,error: nil)
let newState = State.reduce(state, event: .onLoginError(.usernamePasswordMismatch))
let expect = State(username: "beeth0ven",password: "123456",loading: false,data: nil,error: .usernamePasswordMismatch)
newState == expect // 结果:true 😎
}
这样我们可以轻易掌控程序的运行状态,以及各种状态更新。
现在,我们知道如何用 纯函数 做状态管理了。不过当前的代码形态,离投入生产环境,还存在好几个过度形态。这些过度形态有的是围绕如何引入 附加作用,而做了一些应用架构。
在这个问题上,不同地架构也提出了不同的解决方案,如:RxFeedback 用 feedbackLoop
引入 附加作用,Redux 用 middleware
引入 附加作用 等等。这里就不一一介绍了,这些库的官方网站都会有相关说明。
最后,我们还是将代码演化到下一个形态,这里我选择使用 Redux 流派。因为个人的觉得他的知识依赖要少一些,可以让更多读者从中获益。