I have set up a rather large Vuex project with multiple modules.
https://vuex.vuejs.org/en/modules.html
To grab the example of a getter a getter from a search module could be addressed like so:
computed: {
filters() {
return this.$store.state.search.filters;
}
}
Because I need to access the state of the module by referencing the search property in my property chain do I still need to namespace my module?
The documentation states the following:
By default, actions, mutations and getters inside modules are still
registered under the global namespace - this allows multiple modules
to react to the same mutation/action type.
https://vuex.vuejs.org/en/modules.html#namespacing
But if the module is under its own property in the store isn't the only conflict that could happen between modules themselves, which can easily be prevented by a simple naming convention of the files?
What am I missing here?
But if the module is under its own property in the store isn't the only conflict that could happen between modules themselves, which can easily be prevented by a simple naming convention of the files?
No, you misunderstand. The state itself is properly namespaced, but mutations, actions and getters are still collected on a global level so you can e.g. dispatch one Action and several actions from different modules react to it.
That's the default behavior, but the good news is, that there's an option to namespace mutations, actions and getters: "namespaced: true".
it's documented here: https://vuex.vuejs.org/en/modules.html#
Scroll down to the "Namespacing" section.
Related
I'm trying to write SSR-friendly code, keeping in mind a potential migration of my app from SPA to SSR. One of the principles of such code is to avoid statefull singletons which can cause cross request state pollution
The problem comes when I need to use an instance of Vuex, Vue-router, Vue-i18n etc. outside of Vue component. Because the solution in all the respective SO answers is... You guessed it. To create and export a statefull singleton in a separate js file and then import it all over the app:
Vue-router: https://stackoverflow.com/a/43562210/11208064
Vuex: https://stackoverflow.com/a/47575742/11208064
Vue-i18n: https://stackoverflow.com/a/66695008/11208064
A simple example
// store.js
export default new Vuex.Store() {} // this is a singleton
// someOtherModule.js
import { store } from './store.js'
Pinia has covered the issue in the docs. They recommend to access the pinia instance via app.$pinia. However they don't specify how do I access the app instance itself.
Also the problem is not limited to these libraries. We write our own modules which work in a similar manner.
Researching the issue I came across this article. It suggests to wipe module cache, so each time you require it all the code is executed again, making it fresh and stateless. Sounds pretty sophisticated, but maybe this is the way? And if not, what is the recommended solution?
Summary: Can Vuex modules be made $store references in .vue components (instead of referring to the Global Store as it is now after Vue.use(Vuex)) ?
Details:
I read this: vuex modules and I get that the global store can be composed as a bunch of vuex modules.
This is great but is there also a way to make these vuex modules the $store references within vue components instead of $store pointing to the global store (as it is now ?).
This will be mighty useful (IMO) since vue components then have to only be aware of its local store's references (or their own vuex modules); and, how they compose the global store.
Please advise.
I am trying to get better understanding of what the "context" object is in Vuex.
The context object is referred to numerous times in the Vuex documentation. For example, in https://vuex.vuejs.org/en/actions.html, we have:
Action handlers receive a context object which exposes the same set of
methods/properties on the store instance, so you can call
context.commit to commit a mutation...
I understand how to use it, and also that we can use destructuring if we only want to use the "commit" from the context object, but was hoping for a little more depth, just so I can better understand what is going on.
As a start, I found a couple ~8.5 year old posts on the "context object" as a pattern:
what is context object design pattern? and
Can you explain the Context design pattern?
However, specifically to Vuex, I'd love a better understanding of:
What is the context object / what is its purpose?
What are all the properties/methods that it is making available to use in Vuex?
Thank you!
From the documentation you pointed out you can read:
We will see why this context object is not the store instance itself when we introduce Modules later.
The main idea of the context object is to abstract the scope of the current Module. If you simply access store.state, it will always be the root state.
The context object of actions and its properties/methods are described here in the source code and also referenced in the API documentation
Here is the list:
{
state, // same as store.state, or local state if in modules
rootState, // same as store.state, only in modules
commit, // same as store.commit
dispatch, // same as store.dispatch
getters, // same as store.getters, or local getters if in modules
rootGetters // same as store.getters, only in modules
}
As a start, I found a couple ~8.5 year old posts on the "context object" as a pattern ...
I think you're reading into it too much.
I don't think the Vuex docs is referring to some specific kind of "context object" that is known and defined elsewhere, they just mean that the object that is passed to action handlers (and in other situations as described in the docs) is a custom object which they refer to as a "context" object by their own definition.
The reason why they provide this object is because it contains properties that are specific to the module for that particular action handler.
according to the source code of vuex, context is just a literal object with some properties from local, and other properties from store.
The official site of Typescript get me ask a question,
"Do we need to use namespace or not?".
The following quote explains the 2 things well:
It’s important to note that in TypeScript 1.5, the nomenclature has
changed. “Internal modules” are now “namespaces”. “External modules”
are now simply “modules”, as to align with ECMAScript 2015’s
terminology, (namely that module X { is equivalent to the
now-preferred namespace X {).
So, they suggest that TS team prefer namespace.
Further, it says we should use "namespace" to struct the internal module:
This post outlines the various ways to organize your code using
namespaces (previously “internal modules”) in TypeScript. As we
alluded in our note about terminology, “internal modules” are now
referred to as “namespaces”. Additionally, anywhere the module keyword
was used when declaring an internal module, the namespace keyword can
and should be used instead. This avoids confusing new users by
overloading them with similarly named terms.
The above quote is all from the Namespace section, and yes, it says again, but in a internal secnario.
but in the module section, one paragraph, says that:
Starting with ECMAScript 2015, modules are native part of the
language, and should be supported by all compliant engine
implementations. Thus, for new projects modules would be the
recommended code organization mechanism.
Does it mean that I don't need to bother with namespace, use module all along is the suggested way to develop?
Does it mean that I don't need to bother with namespace, use module all along is the suggested way to develop?
I wouldn't put it exactly that way... here's another paraphrase of what has happened. One upon a time, there were two terms used in Typescript
"external modules" - this was the TS analog to what the JS community called AMD (e.g. RequireJS) or CommonJS (e.g. NodeJS) modules. This was optional, for some people who write browser-based code only, they don't always bother with this, especially if they use globals to communicate across files.
"internal modules" - this is a hierarchical way of organising your variables/functions so that not everything is global. The same pattern exists in JS, it's when people organise their variables into objects/nested objects rather than having them all global.
Along came Ecmascript 2015 (a.k.a. ES6), which added a new formal, standard format that belonged in the "external modules" category. Because of this change, Typescript wanted to change the terminology to match the new Javascript standard (being that it likes to be a superset of Javascript, and tries its best to avoid confusion for users coming from Javascript). Thus, the switch of "external modules" being simplified to just "modules", and "internal modules" being renamed to "namespaces".
The quote you found here:
Starting with ECMAScript 2015, modules are native part of the language, and should be supported by all compliant engine implementations. Thus, for new projects modules would be the recommended code organization mechanism.
Is likely alluding to guidance for users who were not yet using (external) modules. To at least consider using it now. However, support for ES6 modules is still incomplete in that browsers as of May 2016 don't have built-in module loaders. So, you either have to add a polyfill (which handles it at runtime) like RequireJS or SystemJS, or a bundler (like browserify or webpack) that handles it at build time (before you deploy to your website).
So, would you ever use both modules (formerly "external modules") and namespaces? Absolutely - I use them both frequently in my codebases. I use (external) modules to organise my code files.
Namespaces in Typescript are extremely useful. Specifically, I use namespace declaration merging as a typesafe way to add extra properties to function objects themselves (a pattern often used in JS). In addition, while namespaces are a lot like regular object variables, you can hang subtypes (nested interfaces, classes, enums, etc.) off of their names.
Here is an example of a function with a property (very common in NodeJS libs):
function someUsefulFunction() {
// asynchronous version
return ...; // some promise
}
namespace someUsefulFunction {
export function sync() {
// synchronous version
}
}
This allows for consumers to do this common NodeJS pattern:
// asynchronous consumer
someUsefulFunction()
.then(() => {
// ...
});
// synchronous consumer
someUsefulFunction.sync();
Similarly, say you have an API that takes in an options object. If that options type is specific to that API,
function myFunc(options?: myFunc.Options) {
// ...
}
namespace myFunc {
export interface Options {
opt1?: number;
opt2?: boolean;
opt3?: string;
}
}
In that case, you don't have to pollute a larger namespace (say whole module scope) with the type declaration for the options.
Hope this helps!
I am in the process of transitioning my 'regular' Backbone projects into a combination of Backbone and RequireJS. While this process works pretty flawless, I still have one question.
Previously I declared a global namespace for my app to which I then bound all my models, views an collections. This is a tip I actually got from the Backbone ToDoMVC project.
So for example, the initialize method of a view could look like this:
initialize: function () {
app.employees = new app.EmployeeCollection();
app.employees.fetch();
}
This works because at the beginning of every file, I've done this:
var app = app || {};
Now when defining my files as AMD modules, the app namespace doesn't exist anymore, which means everything is much more encapsulated:
initialize: function () {
var employees = new EmployeeCollection();
employees.fetch();
}
The EmployeeCollection is loaded with RequireJS:
var EmployeeCollection = require('collections/EmployeeCollection');
Unfortunately I am still very new to Backbone and MVC in general, so I am unsure if this is a good or a bad thing.
What impact will this have on my project – is it okay to use an app namespace like I did previously or does this break any MVC/OOP 'rule'? Are there any Backbone specific consequences I need to be aware of?
Yes, loading the EmployeeCollection via requirejs is a good thing. This explicitly lists each module's dependencies and lets requirejs help you with loading modules in the proper order.
Both the app namespace approach and the requirejs approach are both valid. Backbone won't care which approach you take since with either you have the necessary View/Collection/Model constructor available to use. Personally I like the above benefits I mentioned of requirejs but it's a personal preference you'll have to decide.
However, you shouldn't use requirejs and an all-knowing app namespace together. If you're committed to requirejs then you should only use the app namespace sparingly with top-level data that most of your app will need, rather than attaching all of your requirejs modules to it.
For example, you might use it for a global UserModel that contains information about the current user. To do this you'd create an app object as a requirejs module just like you did with your EmployeeCollection, and then whatever module constructs the UserModel would require 'app' and do a simple assignment: app.user=user.
I said do this sparingly because using a global app namespaces for all your modules would sacrifice much of the benefit of requirejs and would cause you some sequencing pain. Namely:
You can no longer see the actual dependencies for each module declaratively and visualize easily how all your modules fit together. Instead of having the initialize function of your view (or whatever that is) require in 'collections/EmployeeCollection' you'd be requiring 'app'; not a lot of context there.
Requirejs will take care of loading required modules first before allowing your defining function to run. But if everything just requires 'app' then requirejs will only ensure 'app' is defined first and you're on your own for everything else. If app.Bar requires app.Foo, you have to do something to make sure app.Foo gets loaded and defined first.
On a similar note, if requirejs can't figure out all your dependencies because everything just requires 'app' then requirejs's javascript concatenator and optimizer tool (called r.js) will be either useless to you or require a lot of maintenance to add all your modules to a list that it should compile.
If you decide to use requirejs, embrace what it can do for you and just require in the modules you want instead of relying heavily on a global namespace. But there's not a right or wrong way choosing between these two approaches; each is used by lots of smart people.