Vuex State and Getters (2)

To be honest, I wasn't sure what I was writing when I wrote the previous article about Vuex State and Getters. And the more I use Vuex, the more I question this "everything in Getters" proposition. In the end, writing this article allowed me to review the situation.
I know why something did not smell right to me.
The case of the Vuejs components
Several data are accesible within a component, they can come from props
, be defined in data
or be calcultated in computed
.
When we use them in the teplate, we don't ask ourselves the question of their origins, they are all accessible through the this
interface.
Vue.component("ButtonCounter", {
props: {
name: {
type: String,
default: () => "John Doe"
}
},
data: function() {
return {
count: 0
};
},
computed: {
times: function() {
return this.count === 1 ? "time" : "times";
}
},
template: `
<button v-on:click="count++">
Hi {{name}}, you clicked me {{ count }} {{times}}.
</button>`
});
The case of React components
There are two interfaces: this.state
and this.props
. The first handles internal data of the component. The second handles external data of the component whether it comes from the calling component or the state manager.
class ButtonCounter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
render() {
const { count } = this.state;
const { username } = this.props;
const times = count === 1 ? "time" : "times";
return (
<button
onClick={() => {
this.setState({ count: count + 1 });
}}
>
Hi {username}, you clicked me {count} {times}.
</button>
);
}
}
The case of Vuex
Whether the data is directly provided by the state of the store, or the data is derived, we don't have the same interface: this.state
vs this.getters
. And the consumer of the data has to be aware of the internal organization of the store, which is a bit disturbing.
const initialState = {
todos: [
{ id: 1, text: 'Learn about State', done: true },
{ id: 2, text: 'Learn about Getters', done: false }
]
};
function doneTodos(state) {
return state.todos.filter(todo => todo.done)
}
const store = new Vuex.Store({
state: initialState,
getters: {
doneTodos: doneTodos
}
})
To access the todos
, components can add a computed
properties:
Vue.component("TodoList", {
computed: {
todos: function() {
return this.$store.state.todos
},
doneTodos: function() {
return this.$store.getters.doneTodos
}
},
template: `
<ul>
<li v-for="todo in todos" :key="todo.text">
{{ todo.text }}
</li>
</ul>`
});
The case of Redux
Getters are referred to as Selectors and handle providing derived data. In a redux vanilla framework, we will implement a function well-named mapStateToProps
(transforming a data of the global state into a component's props
property).
const initialState = {
todos: [
{ id: 1, text: 'Learn about State', done: true },
{ id: 2, text: 'Learn about Selectors', done: false }
]
};
function doneTodos(state) {
return state.todos.filter(todo => todo.done)
}
const store = createStore(function(state, action) {
if (typeof state === 'undefined') {
return initialState
}
return state;
});
This creates container components (connected to the state manager).
class TodoList extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
render() {
const { todos, doneTodos } = this.pros;
return (
<ul>
{todos.map(todo => (
<li>{todo.text}</li>
))}
</ul>
);
}
}
const mapStateToProps = state => {
return {
todos: state.todos,
doneTodos: doneTodos(state)
}
};
const TodoListContainer = connect(mapStateToProps)(TodoList)
Conclusion
React and Redux don't do something special for computed properties or getters, they are only functions that take a raw data as a parameter and return a computed data.
Vuejs and Vuex treat computed properties and getters in a special way that force developers to adapt their code to the framework (in order to be reactive):
- The Vuejs component that consumes a Vuex data must know how the state is organised;
- Developers need to know the correct interface to access the state data regarding if they are raw or computed data.