Why doesn't (Flux) state management use static functions instead of named properties

Viewed 322

I'm currently deciding between switching to react.js or vue.js from angularJS . The goal is to use it including Typescript to make sure that everything is Typesafe.

With trying out vuex and redux I have noticed that they don't use normal functions but instead use some form of string naming for functions.

Redux for example checks via a switch in reducers for a certain function Image 1

Vuex uses constant objects where the functions in that object can be called via functions which take a string and a payload

Image 2 Image 3

What is the reason for this? Somehow this feels like it's going to be painful when you have to refactor and feels like a way to make mistakes while programming because of typo's.

Why wouldn't a normal class with static functions do the job(or another perhaps better solution) Image 4

1 Answers

Both Redux and Vuex create a single store instance from declared set of modules, that is responsible for dispatching/committing registered actions/mutations that require type to be provided as a string value. While scaling the application, usage of actions/mutations becomes quite widespread and using plain strings will reduce state mutation predictability significantly.

Using constants, such as:

export const ADD_PORTFOLIO = 'ADD_PORTFOLIO'

allows to list all available state mutations in a separate list-like file, thus providing clear understanding of possible changes, while avoiding typos inside store modules and allowing IDE and code editors to autocomplete or highlight invalid references to constant types. Which reduces debugging time and would not be possible with plain strings. It is not required, neither it is an invention of mentioned libraries. It works well with globally invoked events (e.g. Node EvenEmitter, Electron ipcRenderer, etc) for the same reasons.

Both Redux and Vuex store state in plain objects and require their API to be defined as a functions (each with it's own architecture), that will be merged into a single store instance. This serves purpose of providing reactive updates on state changes, warnings when state is mutated outside of mutations or dispatched action/mutation is not registered. My opinion is that this approach is efficient in absence of type safety, which both libraries are initially meant to be used without.

For example, in Vuex if you decide to call an action or mutation from another module, you would use dispatch (for actions) or commit (for mutations) with a type referenced as full path to the module:

dispatch('profile/addPortfolio', payload, { root: true })
commit('profile/ADD_PORTFOLIO', payload, { root: true })

Meaning, that both invocations should be done with store instance methods and are expected to be registered on current store instance, rather than importing and invoking module's action or mutation directly.

In case Typescript is integrated into the project, it is possible to use class-based structure or decorators for the store and it's modules. Again, classes will be compiled to match store library architecture, but enhances development experience.

As for Vuex, following libraries are worth checking out for using with Typescript:

TLDR Such architecture is defined by mentioned libraries for usage without type-safety, while still allowing reactivity and centralized state mutation. Constants help to ensure that actions/mutations are registered on store instance, increase predictability and provide autocomplete for code editors.

Related