-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal for Vuex 5 #1763
Comments
Thank you so much for the proposal. We'll definitely reference this one in designing Vuex 5 👍 |
References to stores sounds very close to what I like this proposal, it addresses some of the current pain points in Vuex 👍 |
Vuex won't use ts to rewrite before Vuex 5? |
@ishowman Correct. We're not planning to rewrite the code base in TS for Vuex 3 or 4. |
Why not use ES classes and all advantages of OOP for store? I created wrapper, which converts ES instance to vuex store. It is simple and provides clear interface for users. Example:
Example, how to access store from vue class method:
I think this is more better design, than use getters/commit/dispatch. You can use inheritance and other OOP features. Source code is simple, you can inspect |
Another proposal here: https://github.com/posva/pinia |
Fyi. I like that. :-) But, what about using a collection of stores in a store? @kiaking |
So yes, Vuex 5 RFC is open. Lets continue the discussions over there 👍 |
What problem does this feature solve?
What does the proposed API look like?
Notice: I haven't implemented a prototype but I have implemented the types of a prototype. I am therefore able to guarantee that all the ideas below are understandable by TypeScript and can produce fully typed stores.
Solution to 1: Vuex 3 state is replaced by innerState, then now state means something else
Here is a first store using a brand new
createStore
API:The
createStore
API takes a builder function as a parameter, which takes no parameter and returns the implementation of a store object. After this function is called bycreateStore
, a store object is generated from the implementation.In our store, the state property is now a read-only object composed by
innerState
andgetters
:Solution to 2: Multiple stores can be easily instantiated using a store builder
If multiple stores need to be created from the same model, then use
createStoreBuilder
. WithcreateStoreBuilder
, the inner builder function can take any parameters. Here is an example:Now, here is how to create the same
category1
as above:The generated builder function simply passes all its parameters to our inner builder function.
Solution to 3: Modules and Root Store are replaced by References to Stores
A store is no longer a tree but a node in a network. The parent-child relationship is replaced by references: each store can be referenced by zero or several stores.
For example, here is how to create a store builder for blog posts, with a reference to a category store:
Then, here is how to create a store named
post1
that has a reference tocategory1
:In the store
post1
, the reference tocategory1
is directly accessible as a read-only propertycategory
:Solution to 3 (bis): References can be single stores, but also: lists, maps, and sets of stores
To illustrate that, let's create a single store
globalData
that references all the existing categories in aMap
:Then, our previous
postBuilder
can be improved usingglobalData
andpayload.categoryId
to get rid of its second parameter:Note: A Map, Set or Array of references that is exposed by a store, is in fact a
ReadonlyMap
, aReadonlySet
or areadonly array[]
. It shouldn't be possible to mutate these collections from outside the store implementation. Only store's mutations can mutate the collections inreferences
.Solution to 4: Types with TypeScript
Typing is provided by inference:
Mutations are called and typed in the same way as direct-vuex:
Typing can be tested by cloning this repo.
Solution to 5: The type of the implementation object
As you may have noticed, the build function passed to
createStore
orcreateStoreBuilder
must return an implementation object that follows a determined structure. Here is this structure in TypeScript syntax:The properties are all optional. The properties
getters
,mutations
,references
are dictionary (key-value) objects.Other points to discuss
Actions are moved out of the store
I suggest removing actions from Vuex because they don't need to have access to the store's internal implementation. By convention, we can call action a function that takes a store as the first parameter, and an optional payload as the second parameter.
It is then not necessary to have a
dispatch
API. Just call the function using the correct store as a parameter when you need it.API that are attached to the store, like
watch
I suggest that additional API that have to be attached to a store, can be grouped in a
st
property (store tools). Then, a store has the following structure:In the types of my proposal, I currently provide the typing of a
watch
object that contains a way to subscribe to each mutation. Maybe not useful.A read-only version of the store
I suggest that each store provides a
readonly
property, which contains a version of the same store but without the ability tocommit
. Its structure could be:But what if I need the root state somewhere?
No, you don't need the whole state of your application. When you need to access the state of a particular store, just reference that store from your store.
Memory and performance
An implementation with a builder function has a trade-off: it doesn't allow to use JS prototypes, and each function (mutation, getter) has to be created for each instance of a store. I guess there is a similar issue with the Vue composition API…
The text was updated successfully, but these errors were encountered: