Elijah Mills
A place to call my own

Enforcing Pure Functions In Alpine.js Apps

To enforce the use of pure functions when using Alpine.js, I have found that the following pattern works well.

First, you should always define your Alpine data object via a function:

function app() { // Data goes here }

Next, instead of just returning the data object, you should assign the data to a variable first, then return that variable:

function app() {
 let rootApp = { // Data goes here }
 return rootApp;
}

The reason for doing this is because it gives us access to rootApp’s properties within nested functions, which becomes important in the next step.

To force ourselves to think functionally and to use pure functions, we should put all methods for the object within a property, making them ‘nested’:

function app() { 
 let rootApp = { 
  name: "App Name", 
  methods: { 
   changeName() { // Do stuff here } 
  }
 } 
 return rootApp; 
}

In the above example, if we try to mutate rootApp’s properties in the changeName() method, it simply won’t work as expected. The data will be changed, but the reactivity of Alpine will break down. This is because Alpine doesn’t watch for this kind of change. We can get around that by wrapping rootApp’s data in Alpine.reactive(), but that lets us break our functional pattern and we don’t want that.

Instead, all methods of the object should simply return a value based on the inputs provided.

Note that changeName() does have access to rootApp’s properties. This means we can use rootApp.name as a starting value and add to or change it, then return the new value if we want.

We also can break the rules slightly by directly mutating rootApp’s properties when we don’t care about reactivity. Yes, we can actually change rootApp’s name in the changeName() function and use that new value later in the function & other functions if we want, but any UI using x-data/x-model, etc… will not update to reflect that change.

I would encourage not directly mutating rootApp’s properties when using this pattern, because then our functions are no longer pure. And the whole point is to force us to have to write pure functions.