Search code examples
javascriptstatealpine.jsglobal-state

AlpineJS: How to create and update global props


I'm new to AlpineJS. I have some production knowledge of React and some basics of Vue. But one of the things I'm not getting about AlpineJS and I did not find a direct answer to this from any of the documentation or tutorial videos on AlpineJS, that's why I'm asking this. It's obviously my lack of knowledge, but I'm afraid, that's true for every newcomer. :)

Suppose, I have the following code (summarized):

<div x-data="{ array1 = [], array2 = [], total = 0 }">
    <!-- ✅ Success: Get user input and populate array1 here -->
    <!-- ✅ Success: Get user input and populate array2 here too -->
    <button x-show="$store.total === 0; console.log("👉 ", $store.total)">
        Do Something
    </button>
</div>

<script>
    const myFunc = (array1, array2, total) => {
        // Reference: https://stackoverflow.com/q/76607996/1743124
        const hash = array2.reduce((h, s) => {
            h[s] = (h[s] || 0) + 1;
            return h;
        }, {});

        array1.map(function(s) {
            if(hash[s] && hash[s]--) {
                console.log("🏌️‍♂️ total ", total);
                Alpine.store('total', total--); // 🟥 QUESTION IS HERE.
                console.log("🕴️ total-- ", total);
                return '✅' + s;
            } else {
                return s;
            }
        });
    }
</script>

The myFunc code is taken from this SO thread.

As you can see that I achieved some of the things. My question is about How can I update the total state from inside the function myFunc and that can be available outside the function for general use?

As in React, we can easily update a state like the below:

// REACT JS EXAMPLE FOR A CONTRAST.

const [total, setTotal] = useState(0);

// Somewhere setTotal(500);

const myFunc = () => {
    setTotal(total--); // under certain condition within a 🔄️ loop
    return true;
};

Here, though the function is returning some other thing, the state is been updated using a setState directive, but we can get the updated value of total anywhere outside.

How can I do a similar thing in AlpineJS? I understood that it can be done using the Store global, but it's not working as expected. The console.logs inside the function were showing exactly what I expected, a 0 (zero) when it should be. But the console.log($store.total) is giving me 1 ⚠️:

All the console.logs

What am I doing wrong here?
Is this a desired effect of the Store global in AlpineJS?

PS. The event that I'm working with is @keyup when all the things are getting fired.


Solution

  • From all I gather, you're simply confused as to why total is 1 within your $store, even though it logs "0" one line later. That's simple JS operator logic, which applies to multiple coding languages.

    Let me explain: You have a "post-" and "pre-decrement" operator (also for increment). It's basically whether the operator is before (pre) or after (post) the variable, and the difference is the order of operations. In the pre operation, the operator is first executed, and then the variable is evaluated. In the post operator, the variable is first evaluated, and then the operator is executed.

    Example:

    let x = 3;
    let y = x--;
    // x = 2, y = 3;
    
    let x = 3;
    let y = --x;
    // x = 2, y = 2;
    

    Basically what is happening, is that you're storing the value of total, and then you're decrementing it. If you're expecting the stored value to be 0, you should use pre-decrement (--total).

    You can read more details about it here.