我們重新走下流程 ??,用 純函數(shù) 做狀態(tài)管理:
typealias UserID = String
enum LoginError: Error, Equatable {
case usernamePasswordMismatch
case offline
}
//首先秉继,我們得有個(gè)狀態(tài)
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)
}
//最后,我們要有一個(gè) 純函數(shù) 來(lái)管理我們的狀態(tài)
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
}
}
現(xiàn)在我們可以在測(cè)試環(huán)境模擬各種事件缘挽,并且判斷結(jié)果是否符合預(yù)期:
//更新用戶名事件
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 // 結(jié)果: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 // 結(jié)果:true ??
}
//觸發(fā)登錄事件
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 // 結(jié)果: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 // 結(jié)果: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 // 結(jié)果:true ??
}
這樣我們可以輕易掌控程序的運(yùn)行狀態(tài)瞄崇,以及各種狀態(tài)更新。
現(xiàn)在到踏,我們知道如何用 純函數(shù) 做狀態(tài)管理了杠袱。不過(guò)當(dāng)前的代碼形態(tài),離投入生產(chǎn)環(huán)境窝稿,還存在好幾個(gè)過(guò)度形態(tài)。這些過(guò)度形態(tài)有的是圍繞如何引入 附加作用凿掂,而做了一些應(yīng)用架構(gòu)伴榔。
在這個(gè)問(wèn)題上,不同地架構(gòu)也提出了不同的解決方案庄萎,如:RxFeedback 用 feedbackLoop
引入 附加作用踪少,Redux 用 middleware
引入 附加作用 等等。這里就不一一介紹了糠涛,這些庫(kù)的官方網(wǎng)站都會(huì)有相關(guān)說(shuō)明援奢。
最后,我們還是將代碼演化到下一個(gè)形態(tài)忍捡,這里我選擇使用 Redux 流派集漾。因?yàn)閭€(gè)人的覺(jué)得他的知識(shí)依賴要少一些切黔,可以讓更多讀者從中獲益。