Why Use Stores Instead of Signals?
Alright there, gang. So in this lesson, I want to talk about another way of managing the state using something called stores. And I mentioned those briefly back when we talked about signals earlier on in the playlist, and I said that although we can use signals to store objects and arrays, they're not optimized as well as stores to deal with them. So instead of using signals for deeply nested objects and arrays, we can use stores instead, which are a little bit more optimized for those types of data.
Because stores treat each object property as its own signal, or each property value as its own signal. And it's the same with arrays; it would treat each item in an array as its own signal, essentially. So when we're updating the values of these objects or arrays, it lets us pinpoint exactly the one part of them that we need to update, and we don't have to treat it so much as a single value as we would when we're using createSignal.
Creating and Accessing Stores with createStore
So let's have a look at some examples of stores now in this SolidJS playground. So I've already created a couple of stores here for us to play around with. And you're going to see we've used this function createStore to create them, and we've imported that up here at the top as well. And this is pretty much the only difference on the surface of things at the minute because before this was createSignal. But we still pass in the same object into this, and we still get two values back in array format. We have person to access the store data, and we have setPerson, which is a setter function to set the new value.
Now we also have an example down here using an array as a value. So createStore again, we pass in the array, and each item in the array is just an object with a title, a price, and an ID. And we call those products and the setter function is setProducts.
Now, the first difference is when we come to access the values, because these are no longer essentially getter functions, but kind of proxy objects. And we don't need to invoke products in order to get it. We don't need to invoke person in order to get it. Instead, we just say person and then dot whatever value we want, so .name.first, .name.last. Down here, we use a For component to cycle through the products. Again, we don't invoke it, and we output a bit of template for each product, just a paragraph tag where we get the title and the price. And we can see those here, and the name's right here.
Updating a Nested Object Property in a Store
The real difference now, apart from non-invoking this, is how we update things. Because like I said a minute ago, SolidJS, when we're using stores, treats each property value as its own signal. So we can update those independently of the entire value. So I'm going to show you how we can do that now.
So first of all, I'm going to come down here and I'm going to place a button at the bottom of the template. And this button is going to be used to, maybe I don't know, change one of the products, update a product. In fact, we'll do one for the name as well. So let's do a button up here, like so, and close this off. And in this one we will say, "Change the last name." So we're going to click on this to update the last name of the person. And then down here we'll say, "Change a product." Okay, so we'll do the name one first of all. So I'm going to say onClick and we set that equal to some kind of function. Now I'm going to call that function changeName, and we need to make it up here.
So let's do a function below this store for the person. So function changeName. And then inside here, we want to use this function setPerson to update the name. So we say setPerson, and previously when we used signals, we'd basically pass through the entire object again. So we'd copy all that, we'd pass it in here, and we'd just change the first name or something. Now we don't have to do that when we're using stores. Instead, we can pinpoint which value or which property we want to update. So I could say, for example, first I want to access the name property, which is this. Then as a second argument, I would want to access the first property, which is this. And then once I've reached my destination, the new value of that will be the third argument, and that could be Mario, for example. So this right here is a path to whatever property we want to update. Okay, let's spell function correctly.
So now when we click on this button down here... change name. Is that working? Okay, I've used a capital here, changeName. So if I click on this, it should update the first name to Mario. We do say "Change the last name." Let's change this to "First." So change the first name, click on that, and it changes it to Mario. So you can look at this as a path to whatever property you want to update. Okay.
Updating an Array Element by Index
All right, so let's do another example with the products. So down here I'm going to create another function. So const... or, rather, we'll just say function changeProduct. And what we'll do is we'll pass in the ID of the product that we want to change. We're not going to use it originally right now, but we will do in a minute. So I'm going to say setProducts in here. And again, we have like a path to the product that we want to update. This time it's an array, so we can pass through the index first of all of the item we want to update. So I could say zero to get the first item in the array, and that's what I want to update. Then it would be the property, so I could change the price property for example. So I'd specify that as the second argument, and then finally the value which could be 25, like so. So now we're updating this 10 value to 25.
I'm going to get rid of that ID because we don't need it just yet. But down here, I'm going to say onClick and I'm going to set that equal to changeProduct, like so. So let me come down here, change the product, and you can see this is now 25 pounds. Awesome. So again, when we're working with arrays, this is like a path to the value that we want to update.
Dynamically Updating an Array Element with a Function
Let me comment this out and do one more example, because as well as a path right here to the array number, the index, we can also use a function. And we can use that for any argument to specify, or to work out, what position or what property we want to update. So let me do an example. setProducts. Now the first argument is going to be a function right here, which finds one of these items. So it will fire a function for each of these items and do a check. If we return true for that particular item, then it will select the item in the array, does that make sense? And update that one.
So what I'm going to do is wrap this inside another inline function just so we can pass through an ID property. So say for example, I want to update the product with the ID of 2, which is this one right here. So now we get the ID as an argument and we can use the ID in this function. So like I said, this function fires for each product, and we get access to that product as an argument, which I'll call p. And I want to return true where p.id is equal to the ID that we pass in. So I'll say p.id is equal to the ID that we pass in, and that means that it's going to return true for this one, because p.id 2 is going to equal 2. So it will select this object right here at this position in the array. For the second argument, again, I'll just say I'll update the price, and then the new value, which is going to be 50. So I think that's pretty much it. So now if I change a product down here, it should be this one that changes to 50, which it does. Awesome.
So hopefully you can see how much easier it is to update different properties or different array elements and properties in those array elements using stores instead of signals. And we're going to be using stores in our project in probably one or two lessons time, but for now, this should give you a general overview of how we create stores and how we update different properties in those stores.