Search code examples
javascriptvue.jsvuexflux

Where to put pre- state setting mutations in Flux Design Pattern


I'm working on an application in Vue with Vuex using the Flux design pattern.

I'm running into what I feel to be bad methodology by having to do small duplications in the code. I'm hoping I'm just seeing something wrong, and that it's just not a shortcoming of this design pattern. (I am new to Flux design pattern)

Here is the situation: I'm reading out to a data source, and getting a list of Users. The Users are set onto their own state object once returned from the API.

Actions -> API -> Mutation -> State

However, there are some time-of-pull computations that need to happen to each user in the list. For example, we have the Date of Birth of each user, but I need to know how old they are. Since mutation methods cannot call other mutation methods, I can not have the setUsers mutation call another mutation to get the age before assigning the list to the state.

If I return the state pre-calculations, then for everywhere I need make the call to setUsers, I'd have to loop over the Users, and call individual mutations for each User to set the age instead of something like this within the mutation:

setUsers(state,users) {
  state.users = setAgeData(users);
},
setAgeData(users) {
  users.forEach(user => {
    user.age = getAge(user.dob);
  });
  return users;
},
getAge(dateString) {
  var today = new Date();
  var birthDate = new Date(dateString);
  var age = today.getFullYear() - birthDate.getFullYear();
  var m = today.getMonth() - birthDate.getMonth();
  if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
    age--;
  }
  return age;
},

Is there any better way to do the on the fly computations before coming back with the state?


Solution

  • setAgeData() and getAge() are not actually mutations (they don't match the signature of a mutation). They should just be utility functions (moved outside the store) that setUsers() calls, and I don't see any problem with that.

    For example, you could move setAgeData() and getAge() into a local function:

    // store/index.js
    function setAgeData() {/*...*/}
    function getAge() {/*...*/}
    
    export default new Vuex.Store({
      mutations: {
        setUsers(state, users) {
          state.users = setAgeData(users)
        }
      }
    })
    

    Or you could move them into a separate file to be imported:

    // store/user-utils.js
    export function setAgeData() {/*...*/}
    export function getAge() {/*...*/}
    
    // store/index.js
    import { setAgeData } from './user-utils'
    
    export default new Vuex.Store({
      mutations: {
        setUsers(state, users) {
          state.users = setAgeData(users)
        }
      }
    })
    

    demo