Comment cet exemple de liaison SwiftUI + état parvient-il à fonctionner sans ré-invoquer le corps?
Un collègue de travail est venu avec l'exemple suivant SwiftUI qui ressemble comme il fonctionne exactement comme prévu (vous pouvez entrer un texte et il devient miroir ci - dessous), mais la façon dont cela fonctionne est surprenant pour moi!
import SwiftUI
struct ContentView: View {
@State var text = ""
var body: some View {
VStack {
TextField("Change the string", text: $text) WrappedText(text: $text)
}
}
}
struct WrappedText: View {
@Binding var text: String
var body: some View {
Text(text)
}
}
Mon modèle mental novice de SwiftUI m'a amené à penser que taper dans TextField changerait la $text
liaison, ce qui à son tour text
muterait la variable @State. Cela invaliderait alors le ContentView
, déclenchant une nouvelle invocation de body
. Mais curieusement, ce n'est pas ce qui se passe! La définition d'un point d'arrêt dans ContentView body
n'est frappée qu'une seule fois, tandis que WrappedText body
est exécuté à chaque fois que la liaison change. Et pourtant, pour autant que je sache, l' text
état est vraiment en train de changer.
Alors, que se passe-t-il ici? Pourquoi SwiftUI ne ré-appelle-t-il pas le corps de ContentView à chaque modification de text
?
Réponses
Lors du changement d'état, le moteur de rendu SwiftUI vérifie d'abord l'égalité des vues à l'intérieur du corps et, si certaines d'entre elles ne sont pas égales, appelle le corps à reconstruire, mais uniquement les vues non égales. Dans votre cas, aucune vue ne dépend (en tant que valeur) de la text
valeur (la liaison est comme une référence - c'est la même chose), donc rien à reconstruire à ce niveau. Mais à l'intérieur, WrappedText
on détecte que Text
avec nouveau text
n'est pas égal à un avec ancien text
, donc body of WrappedText
est appelé à restituer cette partie.
Ceci est déclaré optimisation du rendu de SwiftUI - en vérifiant et en validant la vue modifiée exacte par égalité.
Par défaut, ce mécanisme fonctionne avec les propriétés de structure de View, mais nous pouvons y être impliqués en confirmant notre vue sur le Eqatable
protocole et en le marquant comme .equatable()
modificateur pour donner une logique plus compliquée pour détecter si View doit (ou non) être restitué.