'SwiftUI: prevent View from refreshing when presenting a sheet

I have noticed that SwiftUI completely refresh view when adding sheetmodifier.

Let's say I have View that displays random number. I expect that this value would be independent and not connected to the sheet logic (not changing every time I open/close sheet), but every time sheet presented/dismissed Text is changing.

Is it supposed to work so? Am I wrong that main point of @Sateis to update only connected Views but not all stack? How can I prevent my View from refreshing itself when presenting a modal?

struct ContentView: View {

    @State var active = false

    var body: some View {
        VStack {
            Text("Random text: \(Int.random(in: 0...100))")

            Button(action: { self.active.toggle() }) {
                Text("Show pop up")
            }
        }
        .sheet(isPresented: $active) {
            Text("POP UP")
        }
    }
}

P.S. ContentView calls onAppear()/onDisappear() and init() only ones.



Solution 1:[1]

It needs to make separated condition-independent view to achieve behavior as you wish, like below

struct RandomView: View {
    var body: some View {
        Text("Random text: \(Int.random(in: 0...100))")
    }
}

struct ContentView: View {

    @State var active = false

    var body: some View {
        VStack {
            RandomView()

            Button(action: { self.active.toggle() }) {
                Text("Show pop up")
            }
        }
        .sheet(isPresented: $active) {
            Text("POP UP")
        }
    }
}

In this case RandomView is not rebuilt because is not dependent on active state.

backup

Solution 2:[2]

Asperi sad :

View is struct, value type, if any part of it changed then entire value changed

He is absolutely right! But for that we have state properties. When the view is recreated, the value of state doesn't change.

This should work, as you expected

struct ContentView: View {

    @State var active = false
    @State var number = Int.random(in: 0 ... 100)
    var body: some View {
        VStack {
            Text("Random text: \(number)")

            Button(action: { self.active.toggle() }) {
                Text("Show pop up")
            }
        }
        .sheet(isPresented: $active) {
            Text("POP UP")
        }
    }
}

What is the advantage? For simple things, the state / binding is the best solution, without any doubt.

import SwiftUI

struct SheetView: View {
    @Binding var randomnumber: Int
    var body: some View {
        Button(action: {
            self.randomnumber = Int.random(in: 0 ... 100)
        }) {
            Text("Generate new random number")
        }
    }
}
struct ContentView: View {

    @State var active = false
    @State var number = Int.random(in: 0 ... 100)
    var body: some View {
        VStack {
            Text("Random text: \(number)")

            Button(action: { self.active.toggle() }) {
                Text("Show pop up")
            }
        }
        .sheet(isPresented: $active) {
            SheetView(randomnumber: self.$number)
        }
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Now you can dismiss the sheet with or without generating new random number. No external model is required ...

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2