pointfreeco / swift-composable-architecture

A library for building applications in a consistent and understandable way, with composition, testing, and ergonomics in mind.
https://www.pointfree.co/collections/composable-architecture
MIT License
12.35k stars 1.44k forks source link

Views in `ForEach` recomputed upon element addition #2972

Closed bohdany-cricut closed 6 months ago

bohdany-cricut commented 6 months ago

Description

TCA 1.9.2 (also tested on 1.7.3 and main).

When elements are added to an IdentifiedArray that drives ForEach, every View inside the loop gets recomputed. This behavior is present in both iOS 17+ and earlier versions (with WithPerceptionTracking). I have also tried the old method - using WithViewStore, ForEachStore, and State not being @ObservableState, but it doesn't seem to make any difference.

In vanilla SwiftUI, this does not happen in iOS 17+ with the @Observable macro. Only views corresponding to added elements get recomputed. However, it does happen in vanilla SwiftUI on iOS <17 with the ObservableObject protocol and @Published.

Please refer to the videos below:: Vanilla SwiftUI with @Observable macro: https://github.com/pointfreeco/swift-composable-architecture/assets/118171669/18370627-708f-4991-8a54-aefd3a846a60

TCA: https://github.com/pointfreeco/swift-composable-architecture/assets/118171669/4e7bf5b9-aa85-4614-b1dd-9403adcfce1c

Sidenote:

I am using TCA in a large application with lists containing dozens of heavy views, and adding elements to the driving array while scrolling causes hangs because each view gets recomputed.

Checklist

Expected behavior

Views inside ForEach don't get recomputed, as in vanilla SwiftUI. Ideally on iOS <17 as well.

Actual behavior

Every view that is placed in a ForEach gets recomputed when elements are added to the corresponding array.

Steps to reproduce

Here is a sample project where this issue reproduces. https://github.com/bohdany-cricut/TCA_Perception

  1. Open Project
  2. Uncomment either TCA or SwiftUI version of the view in the TCA_PerceptionApp.swift
  3. Run the App
  4. Observe View updates

The Composable Architecture version information

1.9.2

Destination operating system

iOS 17.2, iOS 15.0

Xcode version information

Version 15.3 (15E204a)

Swift Compiler version information

swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4)
mbrandonw commented 6 months ago

Hi @bohdany-cricut, thanks for bringing this up! It is true this happens in TCA today, and we have plans to address it, but it's going to take time to get there.

Luckily this only affects IdentifiedArray (since it is not observable itself) and further only affects the rows visible on the screen. So hopefully it isn't that big of a deal.

I'm going to convert this to a discussion since it can't be addressed right away, but do know that we are working towards a world where this will be possible. Please feel free to continue the conversation over there if you want.