derivedStateOf VS. remember(key) - THIS is Really the Difference 🤯

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys and welcome back to a new jetpack compos video in this video I will talk about probably the most complex jetpack compos effect Handler that is out there which is called derived State off and I will not only talk about how that effect Handler works but also compare it to using remember with keys because these two variants are actually very similar in what they do but not the same and back then I struggled a lot to really understand the differences so in this video I will go over these so you also understand them now so let's consider the following scenario we have a scroll to top button composable which takes in a lazy list state so a state of a lazy column which contains all kinds of information about how far we scrolled in that lazy column which items are visible about offsets and so on and depending on that scroll position of our lazy column we now want to either show or hide this Floating Action button which can then be used to just scroll to our very top of our lazy column so in the end we just want to say hey if the user scroll past let's say the fifth item of our list then we want to show this little Floating Action button and if we click that we automatically scroll to the very top so far so good but there are multiple ways to achieve that behavior one way would be by doing Val show scroll to top button is by remember and in here we use the derived state of effect Handler that gives us this Lambda scope in which we can then derive a state out of another state so we can say state. first visible item index which is well the the first the the index of the first visible item in our list and if that's at least five for example then we want to show over scroll to job button and if that's not at least five then we don't want to show it and if we Now launch this app and take a look here in our layout inspector let's connect my device here there we go installation failed let's try that again there we go here's our app our lad inspector is connecting so we also see our little UI tree so you can see I have a scaffold here which I just used to show that Floating Action button or hide it in this case and we have a lazy column with a bunch of sample items and right now as you can see there is no Floating Action button down here because we didn't scroll past the fifth item if we do that however if we scroll a little bit then you can see the floating action button suddenly appears we can also take a look here in our scaffold our scroll to toop button has one recomposition and in there we have our Floating Action button which is exactly what is also shown here on the right so from now on as we scroll this remains visible and if we again scroll to the top then it gets hidden again and the way this works is just with this derived State off so it says it deres a state off of another state so in this case our lazy list State already contains all the information we need to compute this other state whether we want to show that button or not so in this case we don't really need to declare another state which we manually need to update and listen to The Lazy list State no we can directly derive off of that so far so good but there's actually another way to do that and the differences between these two ways are actually subtle but very important to know about so let's comment out our approach right here before I also get into the details of how this works I want to show you the other way show scroll to top button and that is using remember just as we did above here but in this case we pass a key here to remember so we say state that first visible item index and then we also say state that first visible item index is at least five because what this will do is if we pass such a key here to this remember function is then jetp compose will listen to changes of these key that we pass here and only if these values change we re-evaluate the expression that we have inside of this remember block and that is in the end exactly the same what we want here again right whenever this first visible item index changes we also want to recheck whether we want to show or hide our scroll to top button if we launch this again and take a look here minimize all that make that a bit bigger here we have our lead inspector you can see right now nothing is showing if we scroll then you can see there is our Floating Action button so that works exactly as before it gets hidden it gets shown again but if we take a look in our scaffold there you can see there are suddenly nine recompositions of our scroll to top button and as we scroll these recompositions are rapidly growing with every single item that we scroll by so why is that let's understand how these two functions actually work behind the scenes so on the one hand remember with keys and derived state of because on the surf they really tend to do the same they listen for changes in another state and then derive a state off of that so let's take a look at remember with keys in the end if we take a look at remember and open the docs here you can see remember is nothing else than a composable function and what that means is compose we'll take a look at the parameters that we pass to this composable function to remember which in this case is our first visible item index and as soon as any of these parameters change so if our key changes then compos will see okay there is actually a composable function inside of the scroll to top button composable that has parameters that has compos states that changed so what I need to do I as the composed compil or the composed runtime rather I need to recompose the scroll to chop button composable because in the end it uses a compos State inside of it that changeed and that is the recomposition we just saw in our layout on Spector another very important thing to note is that the result of this remember calculation is actually just a plain Boolean and it's not a compos state so if we take a look here at show scroll to top button that's just a Boolean that is not a state of type Boolean no it's just a Boolean however if we now take a look at this show scroll to top button with the derived State off variant and we comment out this piece of code if we then take a look here you will see okay that's actually also just a Boolean but that is just because we use this delegate here we can also use equals and then you can see that is actually a state of Ty Boolean in that case we would need to refer to show scroll to Top button. Value since do or compos state but with the delegate we can just get rid of this extra dot value but the important difference here of using derived state of over remember with keys is that this derive State off wrapper will only update the resulting state so the state this show this booleans actually read into it will only update that if the end result of this expression actually changed because the thing is this first visible item index is actually changing much more frequently than the end result so the the end result or actual boo whether to show or hide this Floating Action button changes pretty infrequently it only changes if we scroll past this threshold of the fifth index but this first divisible item index changes with every single item we scroll by so here in this case it doesn't really matter if we already scrolled by the sixth item the seventh item and so on the expression will remain true and that is really the core idea of this derived state of function so the expression in here inside of this derived State off block that will be re-evaluated with every single change of the compos State we use of this block but it will only communicate that change of this final expression to the outside if that really is changed so if that Boolean was really changed from True to false or from false to true and the fact that this is now actually wrapped inside of a compos state which compos really knows and is aware of its changes compos is also smart enough to now recognize that if the end result of this condition actually didn't change it also doesn't need to recompose this scroll to chop button composable okay so far so good but there are actually cases where you don't really notice any difference between using remember and derive s off versus remember with keys there are cases where both of these actually lead to exactly the same result with exactly the same amount of recompositions so what should you pick then to put it in short if you have keys that are changing more frequently than the end result the output of your calculation so all of this condition if the keys are changing more frequently then the end result here then use deriv State off if not so if whenever the key changes the end result is also changing then use remember with a key because the thing is even if the result is the same and you have the same amount of recompositions either approach causes using remember has actually a different purpose than using deriv St off so remember itself really only has the purpose to cash a result across recompositions so you just have some kind of value some kind of compost state or not compost State like we have here inside of this remember block and this function just makes sure that the value here the out come survives recompositions that it stays the same even if this function here is called again by the composed runtime but whenever the key of this remember function actually changes here that also means that new memory has to be allocated for a new result so in this case whenever we scroll just a little bit new memory has to be allocated for the new Boolean that this expression evaluates to while derived set off just make sure to only update the end result and only allocate new memory if the end result really changed and of course the more complex the output of your expression here is maybe you have a very complex data class with sub classes that are also data classes the more complex that is on the one hand the more memory will be allocated and also the more computation effort you have to actually compute this resulting uh data class output so then things can really start to become noticeable okay so I think the difference between these two versions should be clear now however there's one more scenario that could happen to you and now things become a little bit complex and that is is that you sometimes also need to use remember with keys and derived State off because also if we use remember here we have to or we have the option to pass some keys because the way derived state of works is if it's called initially it will just capture all the composed State values that we use in it so in this case it really just the lazy list state which is a compos State and it captures the very initial value it is fed with let's say we now want to extend the scroll to top button with an is enable build Boolean and only if we pass is enabled to True here only then we want to consider this expression so something like this we say and is enabled so if is enabled is false then we will also hide our button regardless of the scrolled index and if we now scroll up here to our little scaffold I haven't showed you till now we also need to pass the is enabled State here so is enabled and for that we can just create a simple compos state is enabled by remember mutable State off and initially let's say our Floating Action button logic is enabled we can then pass it here and just for Simplicity let's say if we click on any of our list items so we add a clickable modifier then we switch that to false so if we Now launch this take a look on our device again then on the first glance everything seems to work just fine if we scroll our button gets shown we scroll to the top it gets hidden again but let's say we now show it and then we click on one of these items which should actually disable the button so it should be hidden afterwards if we do that we click it but the button doesn't really get hidden but that is the expected Behavior right yes it is but as I just described let me shrink that again as I just described what compost will do is it will capture the initial value of all the states that I used instead of this derived State off Handler so the state and the is enable State and it will not track updates to these states so for the State off block the is enabled booing is still true even if it changes for the laser list State we didn't really notice that because the list State itself did never Chang only a property part of that state changed which is the first visible item index but this state never changed so we never set something like um state is equal to a remember lazy list State somewhere else to assign a completely new instance of a lazy list state to it that is why that didn't cause any issues but as soon as we now use this is enabled State we also need to put that as a key here inside of this remember block because what this will do is it will still listen to changes of this is enabled Boolean and if that changes then it will re-trigger this whole derived set off block with the new values so if we now relaunch this take a look here and actually scroll so our button is visible and we click on an item then it automatically gets hidden because our derive State off block is re-executed so now the rules for this become a little bit more complex but as soon as you have composed States inside of your derived set off block that could potentially change over time that could potentially completely be replaced over time such as this this enabled Boolean which can completely change from True to false then that needs to be put as a key for this by remember block if for whatever reason you would also be able to completely replace the lazy list state so if this instance here could completely change then that would also need to be part of this Keys list here but that is typically not the case with lazy list states and those are really all the little traps you can step into with compost which is really simple on the surface but there are so many such caveats under the hood which you really need to take care of so just to summarize if you have a state that is derived from another state just like in this case so we have a Boolean state that is derived from the first visible item index of our lazy column and that state you derive something off so this first visible item index is actually changing exactly as often as the end result as the uh and ruling condition that uh this remember block spits out here then use remember with keys if that's not the case like here where the key actually changes more frequently than the resulting Boolean then use remember with derived State off and if you then have other composed States inside of this derived State off block which could potentially be completely replaced over time like this is enable Boolean these need to be put inside of the keys list of this remember block and I can tell you that is definitely not the only trap you can step into with jetpack compose which is why I have summarized the 20 most common traps people step into with compose which can really cause performance issues they can cause lag they can cause bugs they can even cause crashes and I've condensed them into a PDF which you can download for completely free by using the first link in this video's description so just go there download that PDF I have a lot of code samples in that how you shouldn't do it and how you should do it also with explanations why that is actually the case and other than that I hope you enjoyed this video thanks for watching I will see you back in the next one have an amazing rest of your week bye-bye
Info
Channel: Philipp Lackner
Views: 14,652
Rating: undefined out of 5
Keywords:
Id: _bb0PVBe3eQ
Channel Id: undefined
Length: 14min 45sec (885 seconds)
Published: Wed Feb 21 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.