-
-
Notifications
You must be signed in to change notification settings - Fork 27
-
-
Notifications
You must be signed in to change notification settings - Fork 27
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
Document an alternative approach for Vuex modules #48
Comments
On the topic of Vuex modules, I think the attractiveness is the idea of being able to break your store up into smaller self contained chunks. I am not familiar either but it sounds like it still has a single store.
On a smaller scale I do not think this is much of an issue. I have a scenario with an application where the intent is to manage the architectural data for several organizations. This data, and the resulting screens to manage the data can nest very deep. Here is a simplified structure, and each node might have edit modes / pages or link back to other parts of the application.
On the subject of a new sample, I think a shopping cart could be a good example. You have a user, who can be a guest or be logged in.
|
This is an interesting topic that I would like to chime in on. We have a fairly large enterprise application build with Aurelia, which we have modularized into separate components that are being developed and deployed independently (see this talk on how we're doing this). We've recently started implementing aurelia-store into our application and we've been wondering about how we're going to manage the state of the individual modules. For now, we've settled on simply defining an interface for the state in each module, which derive from an interface defined in the hosting application. That way at least we have some compile time checks to avoid sharing state between modules. That being said, the modules approach does sound interesting. We haven't quite figured out how we're going to clean up state for example, as we move between modules. Keeping all that state in memory for no reason feels wasteful. |
So as far as I understand one of the benefits with VueX Modules is that you can define actions, a slice of the whole state and potentially even middlewares (plugins in VueX) per module. My idea how to target these things in a larger app, as an example based upon @ZHollingshead's shopping cart, perhaps even with a modularized approach like @jmezach mentioned, could look like the following: One single stateI'd still put everything in one state object, which seems to be the same thing VueX does internally as well. So it could look like: // state.ts
export interface State {
// extendable state slices
[slice: string]: StateSlice,
// some global state properties used for the host app
activeTheme: "light" | "dark",
currentPage: string;
}
export interface StateSlice {
} State slicesNow every module defines it's own slice of the state, which gets mapped to a property of the whole state. // product/product.ts
export class Product { name: string; description: string; }
// product/state-slice.ts
export interface ProductsStateSlice extends StateSlice {
products: Product[];
}
// shopping-cart/shoping-cart-item.ts
export class ShoppingCartItem { product: Product; quantity: number; }
// shopping-cart/state-slice.ts
export interface ShoppingCartStateSlice extends StateSlice {
items: ShoppingCartItem[];
} Modules register their custom actions / middlewaresSince Aurelia-Store is built in a way where you can dynamically register/unregister actions and middlewares, once a module gets started do the registration and on unload unregister them again. // product/actions.ts
const initialSliceState: ProductsStateSlice = { products: [] };
export function registerProductSlice(state: State) {
return Object.assign({}, state, { product: initialSliceState });
}
// imaginary main entry of the product-module.ts
import { Store } from "aurelia-store";
function registerModuleInWhateverWay(aurelia: Aurelia) {
const store = aurelia.container.get(Store);
store.registerAction("registerProductModule", registerProductSlice)
store.registerMiddlware(...)
} Module registration of the sliceDepending on how you structure your app, either each module is an aurelia.feature or dynamically loaded with other means. Nevertheless there is one point in time where it registers with Aurelia's DI and at that time it could update the global state, by dispatching a new state and adding the modules state slice as property. function registerModuleInWhateverWay(aurelia: Aurelia) {
...
store.dispatch(registerProductSlice);
} Obtaining only the slice as the whole state per moduleIf a module is only interested in it's own slice as the sole state, a module would subscribe to the following: // imaginary main entry of the product-module.ts
@connectTo({
selector: (store) => store.state.pluck("product"),
target: "state"
})
class ProductModule {
private state: ProductsStateSlice;
} This way the whole // imaginary main entry of the product-module.ts
@connectTo({
selector: {
state: (store) => store.state,
productSlice: (store) => store.state.pluck("product")
}
})
class ProductModule {
private state: State;
private productSlice: ProductsStateSlice;
} Cleaning up after module unloadOnce a module gets disposed/unloaded, we would dispatch a new state and unset the slice // product/actions.ts
export function unsetProductSlice(state: State) {
const { product ...withoutProduct } = state;
return withoutProduct;
} That way the overall state now does not contain anymore the unnecessary slice |
any concerns or ideas with regards to above example @ZHollingshead and @jmezach ? |
@zewa666 I think I like this approach, this keeps things nice and clean. @dannyBies Could you have a look at this as well? I think this could be useful for our scenario, although we need to figure out what would actually trigger unloading a module in our case. |
My initial thoughts are that the above examples seem good to me. I do think it would be nice if you could scope middleware/actions on the module level to keep the modules clean and separated from each other. In the application me and @jmezach are working on we have a modularized approach in which users may end up seeing just one of the modules and never interacting with the others. Scoping the interactions to a module instead of the whole state sounds like an idea worth exploring. I think it could help keep larger applications more organised. |
@dannyBies what would be the effect of scoping though? As far as I see it from Vuex, actions would then only operate on a substate and thus would return a substate, which gets merged with the fullstate. Aside from that I do not see any difference. Wonder what you're exactly thinking about. Maybe you could provide a sample in pseudo-code or whichever way suites you. |
Ah I misunderstood, in cleaning up a module we can of course unregister the middleware/actions related to the module. This approach looks good to me! |
@zewa666 I looked at this and probably over-analyzed it to come to the conclusion that I really like this approach. I think it covers all the major points that I liked about Vuex and seems like something I would enjoy using. |
Awesome, now what really would be cool is to actually build this minimal sample. I'm not sure I can get to it in next time so if anybody wants to take the lead on this it would be very appreciated. |
Ok, I took some time today to play around with it. Here's a sample https://stackblitz.com/edit/aurelia-typescript-y3x3ca Especially take note of my fantastic design skills 🤣 |
seems like we're good here. Closing this for now |
Recently the question about how one can handle large states, or more specifically, how one can leverage a similar system to Vuex modules is popping up all over the places. Here's an example from discourse
Now I do have some thoughts about it, and replied in the topic as well, yet I have to say that I haven't used Vuex to that extent to be able to fully grasp what happens below the surface with modules.
It feels more like a very Vue oriented paradigm and something that could be also achieved with general concepts of RxJS.
So I'd like to get the discussion started about what everyone thinks, would be an use-case that is easily solved with modules and how this could be done with what Aurelia-Store offers for now.
It would be great to come up with a larger sample as well in order to demonstrate the concepts even better. So I'm happy about every contribution.
The text was updated successfully, but these errors were encountered: