0

So I have a marketplace list similar to the code snippet attached. We have a list of marketplace items in the viewmodel being observed as our state. We break down each marketplace item into a lazyitem (side question, does this improve performance, over, say a column, batching all the composables together into one?).

The question I have is a way to map the actual index of each lazy item to the percieved item index, ideally without providing the lazylist state to each composable child (for reusability and/or performance). In the following example, if I were to have two marketplace items in my list, the second without any mediaData, the map should have the following:

0 -> 0

1 -> 0

2 -> 0

3 -> 0

4 -> 1

5 -> 1

6 -> 1

    // this is the state value I want to fill as the lazycolumn gets built
    var perceivedIndexMapper by remember { mutableStateOf(mapOf<Int, Int>()) } 

    var listState = rememberLazyListState()
    val marketplaceItems by viewModel.items.collectAsState() // List items flow

    LazyColumn(
        state = listState
    ) {
       marketplaceItems.forEachIndexed { marketplaceItem, index ->
          item {
             Header(marketplaceItem.headerData, index)
          }
          item {
             Body(marketplaceItem.bodyData, index)
          }

          // Some marketplace items don't have media
          marketplaceItem.mediaData?.let {
             item {
                Media(marketplaceItem.mediaData, index)
             }
          }
          item {
             Footer(marketplaceItem.footerData, index)
          }
       }
    }
rohan
  • 523
  • 1
  • 5
  • 22
  • I can't understand why you should use a Map, or why itemsIndexed() is not enough – Gabriele Mariotti Dec 14 '22 at 17:36
  • itemsIndexed would have a single lazy item for each dataitem we have, however, We want to break down the data model to have mutliple list items per single model. I know we should do this decomposition in the viewmodel or repository layer, but unfortunately, that's not the way the codebase was set up. – rohan Dec 14 '22 at 17:41
  • In you example you just adding a Header and a Body for each marketplaceItem. Why don't use them together in a single item? – Gabriele Mariotti Dec 14 '22 at 17:46
  • @GabrieleMariotti I simplified my use case in the example. In my actual use case, the data models are much more complex, and the items have many more components. – rohan Dec 14 '22 at 18:30

1 Answers1

0

check this

// this is the state value I want to fill as the lazycolumn gets built
var perceivedIndexMapper by remember { mutableStateOf(mapOf<Int, Int>())} 

var listState = rememberLazyListState()
val marketplaceItems by viewModel.items.collectAsState()

LazyColumn(
    state = listState
) {
   itemsIndexed(marketplaceItems) { index, item ->
           Header(marketplaceItem.headerData, index)
           Body(marketplaceItem.bodyData, index)
           item.mediaData?.let {
               Media(marketplaceItem.mediaData, index)
               perceivedIndexMapper.put(index, 0)
           }
           Footer(marketplaceItem.footerData, index)
           
           if(item.mediaData == null) {
               perceivedIndexMapper.put(index, 1)
           }
    }
}

Note

You should understand exactly how the LazyList works! The code above will display as many products as you need and meet the criteria you set. You have one index per product with 0 map value for media and 1 without media. Also you should get this mutable state in another composable function for reuse (State hoisting)

I hope, I helped you

ioanntza22
  • 21
  • 3