To keep a state of primitive values, React's built-in useState hook is ideal. But, for arrays and objects?... It is quite not intuitive nor effective.
Cause ⁉️
The skills required to use spread operator ... to manipulate an array is out of the world. Spread operator is also known to be a key thing that slow things down. It has an O(n) runtime performance which gets hidden behind a cute syntax. But, when it is used too much in ways it was not designed to be used, things gets really messy and it hurts readabilty.
A common pattern we can notice here is that the array is first manipulated and then, to cause a re-render, the array is cloned before setting the state. However, this can lead to big performance issue as cloning an array is not cheap, especially when it contains larger objects in larger quantity.
Solution 💡
I came up with an idea of writing my own hook to handle arrays efficiently. This is inspired by Jetpack Compose's val myList = remember { mutableStateListOf<T>() } (thing!). We can easily manipulate the list like how we do in an imperative fashion. This will trigger recompositions whenever an item is updated, added or removed.
Here's an example of what I mean
@Composable
fun SomeComponent() {
val list = remember { mutableStateListOf<Int>() }
LaunchedEffect(Unit) {
// manipulate list here
list.add(123)
}
// just use the list interface anywhere
list.forEach { item ->
Text(item)
}
}
Without further ado, let's jump right into the code which I implemented.
Declarative UI pattern in blooming and changing how we design and develop UIs. It feels great in every way. All we need is to use these cool stuffs responsively and efficiently such that it doesn't affect readability, performance and hurt peoples' brains.
Problem 😣
To keep a state of primitive values, React's built-in
useState
hook is ideal. But, for arrays and objects?... It is quite not intuitive nor effective.Cause ⁉️
The skills required to use spread operator
...
to manipulate an array is out of the world. Spread operator is also known to be a key thing that slow things down. It has anO(n)
runtime performance which gets hidden behind a cute syntax. But, when it is used too much in ways it was not designed to be used, things gets really messy and it hurts readabilty.A common pattern we can notice here is that the array is first manipulated and then, to cause a re-render, the array is cloned before setting the state. However, this can lead to big performance issue as cloning an array is not cheap, especially when it contains larger objects in larger quantity.
Solution 💡
I came up with an idea of writing my own hook to handle arrays efficiently. This is inspired by Jetpack Compose's
val myList = remember { mutableStateListOf<T>() }
(thing!). We can easily manipulate the list like how we do in an imperative fashion. This will trigger recompositions whenever an item is updated, added or removed.Here's an example of what I mean
Without further ado, let's jump right into the code which I implemented.
This hook allows us to rewrite the
<Old>
component like so:Try it out here: https://replit.com/@pavi2410/React-useArrayState
Similar hooks
This hook is from https://mantine.dev which I didn't know about until midway of writing this 🥲. If I knew already, you wouldn't be here reading this. Anyway, here it is: https://mantine.dev/hooks/use-list-state/
Conclusion
Declarative UI pattern in blooming and changing how we design and develop UIs. It feels great in every way. All we need is to use these cool stuffs responsively and efficiently such that it doesn't affect readability, performance and hurt peoples' brains.