Skip to content
This repository has been archived by the owner on Feb 23, 2023. It is now read-only.

State Management

Jordan Langton edited this page Jul 21, 2020 · 1 revision

What is State

State is a way to mannage the "state" of your application. It is the single source of truth and holds the whole state tree. In truth, it is just an object. To change the state, you must Commit a mutation to it. For instance if you have a username inside your View Controller. And you display it as a heading in your template.

<template>
  <h1>{{username}}</h1>
</template>
  ActiveJS.newController("State_Management", {
    el: "#app",
    Data() {
      return {
        username: "John"
      }
    }
  })

Now if you update username via a method inside your View Controller. This is all good, but what happens when you change to another view and come back? The username property will now be set back to it's initial value when you load the view. This is where State comes into the picture!

Lets Get Started

Inside the ./public at the root of the application. you'll find a file called app.state.js. In this file you'll find an exported object which contains four properties ( state, getters, mutations, actions ). Read more to find out what each of these properties do.

export default {

  "model": {
    // where you store global data
  },
  "getters": {
    // where you store your getters for properties in the model
  },
  "mutations": {
    // where you store your setters for properties in the model
  },
  "actions": {
    // where you store your async methods
  },

};

Context Object

The context is an object with access to your properties inside your state object. It is passed to all methods inside your getters, mutations and actions. The context object allows you to get properties out of your state or call a method from your mutations or actions. Below is a table showing every property inside the context Object.

Propery Type Description ( --------- )
$model Object A reference to the model object example
$mutaions Object A reference to the mutaions object example
$actions Object A reference to the actions object example
Get Method Allows you to call a method inside your getters object example
Commit Method Allows you to call a method inside your mutations object example
Dispatch Method Allows you to call a method inside your actions object example

The Model Object

The model property is the main object of variables/properties in which you will be storing and minipulating data. For example you could add a property to the state called users. And this could be an array of user objects.

"model": {
  users: [
    {name: "James", age: 15},
    {name: "Fred", age: 34},
    {name: "John", age: 22}
  ]
}

The Getters Object

The getters property will be an object of methods. The method's job is to get values out of your model. For example, lets say you want to get the user james out of your array of users we showed you above. You would create a getter method. Lets call it getUser(). How do we access the model? Well, all getters get passed the context object and a payload that you set when calling a getter. See the example below.

"getters": {
  getUser(context, payload) {
    const user = context.$model.users.filter(user => {
      return user.name == payload.name;
    });

    return user;
  }
}
// using a 'getter' method in your view
ActiveJS.newController("State_Management", {
  el: "#app",
  Data() {
    return {
      username: "John"
    }
  },
  methods: {
    getUsers() {
      ActiveJS.State.Get("getUser", {name: this.username});
    }
  }
})

The Mutations Object

The mutations property holds all your methods that update or change your model. Just like we explained above, all mutations get passed the context object, and a payload you set.

As an example, lets say you want to update the user within the model called "James" to a name you pass in your payload. We would then create a mutation with a name along the lines of "updateUser()" which would do so. As you can see we decontruct the context object only to use the model from it, See example below.

NOTE : All mutaions need to be synchronous to ensure that the state isn’t dependent on the timing and order of unpredictable (asynchronous) events.

"mutations": {
  updateUser({$model}, payload) {
    $model.users.forEach((user, index) => {
      if(user.name == payload.name) {
         $model.users[index].name = payload.newName;
      }
    });
  }
}
// using a 'getter' method in your view
ActiveJS.newController("State_Management", {
  el: "#app",
  Data() {
    return {
      inputValue: "John"
    }
  },
  methods: {
    updateUser() {
      ActiveJS.State.Commit("updateUser", {name: "Fred", newName: this.inputValue});
    }
  }
})

The Actions Object

The actions property is very similar to the mutations property, but there is one key difference between a mutation method and an action method. All actions are for asynchronous calls and should NEVER update or change the model itself. Rather you should call a mutation once you have the asynchronous data and pass it as a payload.

For example, say we have a table in a database which conatins all our users. Now we want to get a user and then insert him/her into our model. Here is where an action will come into play. Lets call this action getUserFromDB(), and fetch the user from our database. Once we get the user, we can call a mutaion to insert the user we just got back. See example below.

"actions": {
  getUserFromDB({Commit}) {
    fetch("https://someApi/users")
    .then((response) => {
      if(response.status != 200) {
        console.error("Request failed with a status of : "+response.status);
        return;
      }

      // call mutation to insert user
      Commit("insertUser", JSON.parse(response.result));
    })
    .catch((err) => {
      console.error("Request failed : "+err);
    })
  }
}