William T.
William T.

Reputation: 14321

How to update ChildView's @State var when ParentView view doesn't want to Bind?

I have a child view that shows a date, so it has a simple date var, it's pretty straight forward.

struct ParentView: View {
    var body: some View {
        ChildView(date: Date())
    }
}

struct ChildView: View {
    var date: Date
    
    var body: some View {
        Text("") //show date
    }
}

The above works fine, but the problem comes when, in the ChildView, I want to make the date a @State variable so ChildView UI elements can be updated, for example, if I have a date picker in the ChildView.

When I make this a @State var, the ChildView no longer receives updates from the parent anymore, even if the ParentView changes the date and re-calls the ChildView. It's always just stuck with whatever the initial date that was given to it on first load.

The ParentView does not want to bind the child date because the ParentView doesn't care how the date is altered in the ChildView.

Any ideas how to get this to work?

Upvotes: 1

Views: 956

Answers (1)

aheze
aheze

Reputation: 30228

You could try two @State properties — one in the parent and one in the child view. You can then observe the parent property using onChange, and update the child property.

struct ContentView: View {
    @State var actualDate = Date() /// Store the actual date here.

    var body: some View {
        VStack {
            Button("Reset actual date") {
                actualDate = Date()
            }

            ChildView(actualDate: actualDate) /// Pass in the actual date.
                .padding()
                .background(Color.yellow)
                .cornerRadius(16)
                .padding()
        }
    }
}

struct ChildView: View {
    var actualDate: Date
    @State var editableDate: Date

    init(actualDate: Date) {
        self.actualDate = actualDate
        self._editableDate = State(initialValue: actualDate) /// Set `editableDate`'s initial value to the actual date.
    }

    var body: some View {
        DatePicker("Date", selection: $editableDate)
            .onChange(of: actualDate) { newValue in /// Whenever the actual date changes, update `editableDate`.
                editableDate = newValue
            }
    }
}

Result:

Date is initially December 8. I then use the date picker to change it several times. Pressing the Reset button resets it to December 8.

Upvotes: 1

Related Questions