Is it right that TabRow recomposes all tabs each t...
# compose
j
Is it right that TabRow recomposes all tabs each time you make a selection?
🤔 1
For instance:
Copy code
@Composable
fun TabRow2(
) {

	var selectedTab by remember { mutableStateOf(0)}

	TabRow(
		selectedTabIndex = selectedTab,
		indicator = { tabPositions ->
			if (selectedTab < tabPositions.size) {
				TabRowDefaults.SecondaryIndicator(
					Modifier.tabIndicatorOffset(tabPositions[selectedTab])
				)
			}
		},
	) {

		for (i in 0 until 4) {
			println("new tab $i")
			Tab(
				selected = selectedTab == i,
				onClick = { selectedTab = i },
				text = { Text(i.toString()) }
			)
		}

	}

}
I would have expected that to only recompose the indicator or maybe the two tabs affected by the change, no?
p
Any time you use
for
loop, you should consider using
key()
Copy code
for (i in 0 until 4) {
    val isSelected = i == selectedTab
    key(i, isSelected) {
        Tab(selected = isSelected, ...)
    }
}
j
good point, but it still recomposes the whole thing.
is it because the function takes an int instead of a lambda?
p
I made a typo. I updated the code above, try again :)
Any time arguments for composable change, it's subject to recompose
j
It still rebuilds all tabs, regardless of key.
here's the test I used now:
Copy code
@Composable
fun TabRow2() {

	var selectedTab by remember { mutableStateOf(0)}

	TabRow(
		selectedTabIndex = selectedTab,
		indicator = { tabPositions ->
			if (selectedTab < tabPositions.size) {
				TabRowDefaults.SecondaryIndicator(
					Modifier.tabIndicatorOffset(tabPositions[selectedTab])
				)
			}
		},
	) {

		for (i in 0 until 4) {
			val isSelected = i == selectedTab
			key(i, isSelected) {
				println("new tab $i")
				Tab(
					selected = selectedTab == i,
					onClick = { selectedTab = i },
					text = { Text(i.toString()) }
				)
			}

		}

	}

}
Here's TabRow's signature:
Copy code
@Composable
@ComposableInferredTarget
public fun TabRow(
    selectedTabIndex: Int,
    modifier: Modifier,
    containerColor: Color,
    contentColor: Color,
    indicator: @Composable (List<TabPosition>) -> Unit,
    divider: @Composable () -> Unit,
    tabs: @Composable () -> Unit
): Unit
to me it seems like it shouldn't accept selectedTab as an Int if that causes every tab to rebuild on change.
but it also uses subcomposelayout, and I don't see why that's needed, so maybe there is extra magic to it that I don't understand