can't use @Environment for Binding?

@Environment can't use for Binding?

@Observable
final class View1Model {
  var text: String = ""
}

struct View1: View {
  @State var viewModel = View1Model()
  var body: some View {
    View2()
      .environment(viewModel)
  }
}

struct View2: View {
  @Environment(View1Model.self) var viewModel
  
  var body: some View {
    TextField("Text", text: $viewModel.text) // Cannot find '$viewModel' in scope
  }
}
Answered by zunda in 762819022
struct TitleEditView: View {
  @Environment(Book.self) private var book


  var body: some View {
    @Bindable var book = book
    TextField("Title", text: $book.title)
  }
}

I found this from Bindable Document https://developer.apple.com/documentation/swiftui/bindable

thanks @macrojd

Why don't you declare an environmentObject ?

 @EnvironmentObject var viewModel: View1Model

I also had that problem, this is the solution: add @Bindable var viewModel = viewModel in your view’s body, even though I don’t think it is elegant.

@Observable
final class View1Model {
  var text: String = ""
}

struct View1: View {
  @State var viewModel = View1Model()
  var body: some View {
    View2()
      .environment(viewModel)
  }
}

struct View2: View {
  @Environment(View1Model.self) var viewModel
  
  var body: some View {
   // use @Bindable to get the binding  
    @Bindable var viewModel = viewModel
    TextField("Text", text: $viewModel.text) 
  }
}

This code has good performance. But it is not cleaner than @EnvironmentObject

struct View2: View {
  @Environment(View1Model.self) var viewModel
  
  var body: some View {
    TextField("Text", text: Binding(get: {
      viewModel.text
    }, set: { newValue in
      viewModel.text = newValue
    }))
  }
}

The most elegant solution I've found is to extract the view and pass the model to a @Bindable property.

@Observable
final class View1Model {
  var text: String = ""
}

struct View1: View {
  @State var viewModel = View1Model()
  var body: some View {
    View2()
      .environment(viewModel)
  }
}

struct View2: View {
  @Environment(View1Model.self) var viewModel
  
  var body: some View {
    View3(viewModel: viewModel)
  }
}

struct View3: View {
  @Bindable var viewModel: ViewModel
  
  var body: some View {
    TextField("Text", text: $viewModel.text)
  }
}

You can also create an inline bindable:

TextField("Text", text: Bindable(viewModel).text)
Accepted Answer
struct TitleEditView: View {
  @Environment(Book.self) private var book


  var body: some View {
    @Bindable var book = book
    TextField("Title", text: $book.title)
  }
}

I found this from Bindable Document https://developer.apple.com/documentation/swiftui/bindable

thanks @macrojd

can't use @Environment for Binding?
 
 
Q