Skip to content

Instantly share code, notes, and snippets.

@morajabi
Last active October 16, 2024 12:28
Show Gist options
  • Save morajabi/3020dc40b7eb23a37c99a409e5a865de to your computer and use it in GitHub Desktop.
Save morajabi/3020dc40b7eb23a37c99a409e5a865de to your computer and use it in GitHub Desktop.
Form state management in Swift UI
import SwiftUI
struct FormStateData {
var loading: Bool
var error: String?
var succeeded: Bool?
}
// A helper for easier state management for simple forms
class FormState: ObservableObject {
@Published private(set) var state: FormStateData
// Streamlined access
var isLoading: Bool { state.loading }
var hasError: String? { state.error }
var hasSucceeded: Bool? { state.succeeded }
init() {
self.state = FormStateData(loading: false, error: nil, succeeded: nil)
}
func reset() {
state = FormStateData(loading: false, error: nil, succeeded: nil)
}
func startLoading() {
state = FormStateData(loading: true, error: nil, succeeded: nil)
}
func failed(error: String?) {
state = FormStateData(loading: false, error: error, succeeded: false)
}
func succeeded() {
state = FormStateData(loading: false, error: nil, succeeded: true)
}
}
@morajabi
Copy link
Author

You can also use it as a property wrapper by modifying it like this:

@propertyWrapper
struct FormState: DynamicProperty {
    @StateObject private var state = FormStateObject() // Renamed from FormState to avoid conflict with property wrapper name
    
    var wrappedValue: FormStateObject {
        state
    }
}

Usage:

struct FormView: View {
    @FormState var formState

   // var body ...
}

@dena-sohrabi
Copy link

Refactored FormStateData to use enum instead of struct

import SwiftUI

public enum FormStateData: Equatable {
    case idle
    case loading
    case error(String?)
    case succeeded
}

// A helper for easier state management for simple forms
public class FormStateObject: ObservableObject {
    @Published public private(set) var state: FormStateData

    public var isLoading: Bool {
        state == FormStateData.loading
    }

    public init() {
        self.state = .idle
    }

    public func reset() {
        state = .idle
    }

    public func startLoading() {
        state = .loading
    }

    public func failed(error: String?) {
        state = .error(error)
    }

    public func succeeded() {
        state = .succeeded
    }
}

@propertyWrapper
@MainActor
public struct FormState: DynamicProperty {
    @StateObject private var state = FormStateObject()

    public init() {}
    public var wrappedValue: FormStateObject {
        state
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment