How to use EquatableView in TCA?

Hi, I'd like to know whether it's possible to override the diffing? I'm hitting some performance bottlenecks because my view is re-rendering but I'm not sure what's the right protocol here. In plain views EquatableView / Equatable should do the trick. In views that use a viewStore I suspect this could work differently?

Default initialiser for WithViewStore accepts removeDuplicates:. You can read more in documentation here.

1 Like

Isn't it better to use SwiftUI EquatableView instead of the removeDuplicates? I can see how the state comparison works just fine but what if SwiftUI has performance optimizations for EquatableView?

AFAICT, the real usefulness of EquatableView lies in being able to define your own equality logic where view equality can't be determined based purely on the state's raw value alone. To take a contrived example, imagine a view that has a counter that renders a Circle in a different color based on whether or not the counter is odd or event:

struct CircleView: View {
  var store: Store<CounterState, Void> // CounterState == Int

  var body: some View {
    WithViewStore(store) { viewStore in
      Circle().backgroundColor(
        (viewStore.state % 2 == 0) ? Color.red : Color.green
      )
    }
  }
}

Even though this view is carefully scoped to only the state it cares about, it will still re-evaluate the WithViewStore body every time the counter value changes - ideally the view should only re-evaluate if the counter's even-ness changes which we can't determine purely by == alone.

Now if this was a pure SwiftUI implementation and you were using @State then the only way you have of refining this behaviour is to make your view Equatable and define a custom == function for the view that compares the even-ness of the state.

In this case though the state changes are being driven by the ViewStore which allows you to define your own removeDuplicates: as @eimantas mentioned so you could instead just pass in a custom implementation that removed duplicates based on even-ness of the state and the contents of the WithViewStore body will only be re-calculated when that changes.

If there's any optimisations in SwiftUI its more likely to be in the rendering pass rather than the body calculation phase. Even if your view body is re-calculated I think SwiftUI is generally smart enough not to re-render it if the resulting view body is unchanged, but avoiding unnecessary body re-evaluations is just another layer of optimisation you can achieve by carefully scoping your view state and I think either a custom removeDuplicates implementation of using an equatable view would have the same effect.

a custom removeDuplicates implementation of using an equatable view would have the same effect.

I don't think that's true. I have this ItemCell I use in lazy grid view or lazy hstack.

Without Equatable:

With Equatable:

image

Using Equatable seems to make a huge difference.

@mbrandonw can you provide some guidance on this?

1 Like

Also this The Mystery Behind View Equality - The SwiftUI Lab