Welcome to the “Passing @State to Subviews” demo. In this demo, you’ll learn how to share state between views in SwiftUI. You’ll use the simple counter app to demonstrate this concept. Time to get started!
First, open the starter Counter Xcode project in the 07-Passing-@State-to-Subviews-Demo/Starter directory. This project contains all the starter code you’ll need for this demo.
In the CounterApp.swift
file, you’ll find the CounterView
struct. This view displays the current count and includes buttons to increment and decrement the count:
struct CounterView: View {
@State private var count: Int = 0
var body: some View {
VStack {
Text("Count: \(count)")
Button("Increment") {
count += 1
}
Button("Decrement") {
count -= 1
}
}
}
}
In the same file, you’ll see the ContentView
struct. It currently looks like this:
struct ContentView: View {
var body: some View {
VStack {
CounterView()
}
}
}
In this setup, ContentView
simply displays CounterView
. Run the app to see the counter in action. Tap the Increment and Decrement buttons to change the count.
To practice sharing state, modify CounterView
to receive the count as a parameter instead of managing its own state. This change will demonstrate how to pass state from a parent view to a subview.
Replace the @State property: In the original CounterView
, there’s a line defining a @State
property for the count. Replace this line with a constant property, as CounterView
will now receive the count value as a parameter from its parent view:
struct CounterView: View {
let count: Int
var body: some View {
VStack {
Text("Count: \(count)")
Button("Increment") {
count += 1
}
Button("Decrement") {
count -= 1
}
}
}
}
Add an initializer: To set the count
property when creating an instance of CounterView
, add an initializer to the struct. This initializer takes the count value as a parameter and assigns it to the count
property:
struct CounterView: View {
let count: Int
init(count: Int) {
self.count = count
}
var body: some View {
VStack {
Text("Count: \(count)")
Button("Increment") {
count += 1
}
Button("Decrement") {
count -= 1
}
}
}
}
Update the body property: In the body of the CounterView
, remove the Button
views. You should have a Text
view that displays the count:
struct CounterView: View {
let count: Int
init(count: Int) {
self.count = count
}
var body: some View {
VStack {
Text("Count: \(count)")
}
}
}
By following these steps, you’ve updated CounterView
to receive the count as a parameter from its parent view and display it in a Text
view.
Notice that CounterView
no longer has a @State
property. It now has a constant property count
that it uses to display the count value. CounterView
is stateless.
Move @State to the parent view: Update ContentView
to manage the state and pass it to CounterView
. Then, add a count
@State
property:
struct ContentView: View {
@State private var count: Int = 0
var body: some View {
VStack {
CounterView()
}
}
}
Next, pass the count into the child subview CounterView
:
struct ContentView: View {
@State private var count: Int = 0
var body: some View {
VStack {
CounterView(count: count)
}
}
}
Lastly, add the increment and decrement buttons to ContentView
:
struct ContentView: View {
@State private var count: Int = 0
var body: some View {
VStack {
CounterView(count: count)
Button("Increment") {
count += 1
}
Button("Decrement") {
count -= 1
}
}
}
}
In this updated version, ContentView
has a @State
property count
that it passes to its child CounterView
. ContentView
also includes the buttons to increment and decrement the count. When you tap the buttons, ContentView
updates its state, and CounterView
automatically reflects the changes.
Run the app again to see the behavior. You’ll notice that the count updates as before, but now the state is managed by ContentView
and passed to CounterView
.
This demo illustrates how to pass state from a parent view to a child subview in SwiftUI. That’s it for this demo. Next is the lesson’s conclusion, which wraps up everything you’ve learned about @State
in SwiftUI.