💡

SwiftUI Idea - Bindingを発行するcomponent

2023/05/30に公開
  • Bindingを求めるコンポーネントがある
  • Bindingを発行するには主にStateが必要
  • 簡単な方法はwrapperとなるviewを作りそこにStateを持たせること
  • ユースケースが単純であれば一般化したコンポーネントにしてwrapperの作成を省略できる
  • LocalStateとして一般化されたコンポーネントを実装する

Example

  struct ComponentState: Equatable {
    var a = "1"
    var b = "2"
    var c = "3"
  }

  var body: some View {
    VStack {
      LocalState(
        initial: ComponentState(),
        onChange: { print($0) }
      ) { state in
        TextField("A", text: state.a)
        TextField("B", text: state.b)
        TextField("C", text: state.c)
      }
    }
  }

Implementation

public struct LocalState<State: Equatable, Content: View>: View {

  @SwiftUI.State var state: State

  private let content: (Binding<State>) -> Content

  private let onChange: (State) -> Void

  public init(
    initial: State,
    onChange: @escaping (State) -> Void = { _ in },
    @ViewBuilder content: @escaping (Binding<State>) -> Content
  ) {
    self.onChange = onChange
    self._state = .init(initialValue: initial)
    self.content = content
  }

  public var body: some View {
    content($state)
      .onChange(of: state) { newValue in
        onChange(newValue)
      }
  }

}

Discussion