-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Could a feature (autoToRef) be implemented to automatically return (toRefs) when destructuring the state? #718
Comments
One or multiple example would help understand what you want by auto refs and also if it's technically possible or not. Also note that you don't need to use |
what I meant was that it's a bit annoying to import all the time storeToRefs, what I mean would be this: import { useMainStore } from "~/stores/mainStore";
import { storeToRefs } from "pinia";
const mainStore = useMainStore();
const { foo, bar } = storeToRefs(mainStore); I think if there was an option (autoToRef) where I could decide if I want the storeToRefs to be done automatically when the store is destructuring that would be great. import { createApp } from "vue";
import { createPinia } from "pinia";
import App from "./App.vue";
const pinia = createPinia({
autoToRef: true,
});
const app = createApp(App);
app.use(pinia);
app.mount("#app"); then I would only have to do: import { useMainStore } from "~/stores/mainStore";
const { foo, bar } = useMainStore(); maybe this package will help you to better understand the idea, I repeat I am a newbie, it is just an idea, but not a bad one. |
Maybe this is possible with a vite plugin and I'm open to adding it to the main repo but I don't have the bandwidth to do it. Another solution is to create your own I think that last version is the most interesting one |
Could someone exemplify how would be this custom function that would allow to destructure anything? |
this is my solution to this: store example: import { defineStore } from "pinia";
const store = defineStore("global", {
state: () => ({
previousRoute: "",
}),
});
export default store; @helpers/pinia-auto-refs.js import { storeToRefs } from "pinia";
const storeFiles = import.meta.globEager("./../store/*.js");
let storeExports = {};
for (const fileName in storeFiles) {
const { default: storeObject } = storeFiles[fileName];
storeExports[storeObject.$id] = storeObject;
}
export function useStore(storeName = "global") {
if (!Object.keys(storeExports).includes(storeName)) {
throw "Unknown pinia store name: " + storeName;
}
const store = storeExports[storeName]();
const storeRefs = storeToRefs(store);
return { ...store, ...storeRefs };
} and unplugin autoimports config: {
dts: "auto-imports.d.ts",
include: [
/\.vue$/,
/\.vue\?vue/, // .vue
],
imports: [
// presets
"vue",
"vue-router",
{
"@helpers/pinia-auto-refs.js": ["useStore"],
},
],
} add unplugin to vite config plugins: import unpluginAutoImport from "unplugin-auto-import/vite";
//..
plugins: [
// ...
unpluginAutoImport(unpluginAutoImportConfig),
// ...
] example usage: const { statePropExample, getterExample, actionExample } = useStore("storeName");
// leave useStore() to access to store named global -> useStore("globall") pros:
cons:
|
I have an alternative for my // defineRefStore.js
import { defineStore, storeToRefs } from "pinia";
export function defineRefStore(id, storeSetup, options) {
const piniaStore = defineStore(id, storeSetup, options);
return () => {
const usedPiniaStore = piniaStore();
const storeRefs = storeToRefs(usedPiniaStore);
return { ...usedPiniaStore, ...storeRefs };
};
} also a d.ts file for intelisense // defineRefStore.d.ts
import {
DefineSetupStoreOptions,
_ExtractStateFromSetupStore,
_ExtractGettersFromSetupStore,
_ExtractActionsFromSetupStore,
Store,
PiniaCustomStateProperties,
} from "pinia";
import { ToRefs } from "vue-demi";
export declare function defineRefStore<Id extends string, SS>(
id: Id,
storeSetup: () => SS,
options?: DefineSetupStoreOptions<
Id,
_ExtractStateFromSetupStore<SS>,
_ExtractGettersFromSetupStore<SS>,
_ExtractActionsFromSetupStore<SS>
>
): () => Store<
Id,
_ExtractStateFromSetupStore<null>,
_ExtractGettersFromSetupStore<null>,
_ExtractActionsFromSetupStore<SS>
> &
ToRefs<
_ExtractStateFromSetupStore<SS> &
_ExtractGettersFromSetupStore<SS> &
PiniaCustomStateProperties<_ExtractStateFromSetupStore<SS>>
>; now when defining stores just use example: import { defineRefStore } from "./defineRefStore.js";
import { ref, computed } from "vue";
export const useCartStore = defineRefStore("cart", () => {
const products = ref([]);
return { products };
}); NOTE I WROTE THIS FUNCTION ONLY FOR SETUP STORES |
Hi,I implemented ts version based on your idea.And publish it as a Vite plugin.I used it in one of my projects and it worked fine and looked fine.It's easy to use and has intelisense. |
Couldn't this be done as a helper of sorts? const warehouseStore = useWarehouseState();
const { setWarehouseState } = warehouseStore;
const { warehouse, resourceVolume } = storeToRefs(warehouseStore); As an example, this is quite annoying. Couldn't this be wrapped up into a helper function that returns a combined object to the effect of: // Contrived example, but internally the helper would do something similar?
function someHelper() {
const warehouseStore = useWarehouseState();
const { setWarehouseState } = warehouseStore;
const { warehouse, resourceVolume } = storeToRefs(warehouseStore);
return {
setWarehouseState,
warehouse,
resourceVolume
};
} Which we could then use as: const { warehouse, resourceVolume, setWarehouseState } = someHelper(useWarehouseState()); Or does this just end up breaking things? |
Found this annoying as well. There's no point in unwrapping all refs in a setup store, since everything returned from it will already have been a ref/reactive/computed or marked raw. I ended up writing this version of defineStore which includes a modified version of storeToRefs in it.
https://gist.github.com/unshame/1deb26be955bc5d1b661bb87cf9efd69 const useInnerStore = defineStore('innerStore', () => {
return {
innerRef: ref('baz'),
};
});
const useStore = defineStore('store', () => {
return {
reactiveProp: reactive({ field: 'foo' }),
refProp: ref('bar'),
rawProp: markRaw({ key: "I'm raw" }),
...useInnerStore(), // combining stores
};
});
const { reactiveProp, refProp, rawProp, innerRef } = useStore();
console.log(reactiveProp.field); // foo
console.log(refProp.value); // bar
console.log(isRef(rawProp) || isReactive(rawProp)); // false
console.log(innerRef.value); // baz The only downside is that some internal types had to be imported and rewritten to remove Unwrap from them. |
@vieruuuu Love your work! I think your thin wrapper over
with defineRefStore:
|
Proposal for --> store const show = getter(false); // same as a ref
const countObj = reactiveGetter({ count: 0 }); // same as reactive
const user = ref(false); // not exported
const getUser = () => console.log('user'); --> component const { show, countObj, getUser } = useUserStore(); Essentially this would mean that To get a |
It would be better if it didn't get converted to reactive in the first place, instead of turning it into reactive and then back into refs. |
See my issue: #2504 (comment) |
Edit: this doesn't always work, I added some more code and it broke reactivity again, no clue what's up with this. I don't know if this solves things for you guys, but I ran into this while coding an example application for an assignment: here's my store: import {ref} from 'vue'
import {defineStore} from 'pinia'
export const useTodoStore = defineStore('counter', () => {
const todos = ref<{text:string, completed:boolean}[]>([])
function addTodo(todo: {text:string, completed:boolean}) {
todos.value.push(todo)
}
return {todos, addTodo}
}) here's how I destructure it const {todos, addTodo} = useTodoStore() this destructures the store with the todos ref still functioning as intended (it can be updated and my template adjusts accordingly) which would not be possible if I had done: const store = useTodoStore()
const {todos, addTodo} = store might be intended, might not be, either way, seems to be a good fit for this issue and I didn't see anyone bring it up. |
Using
|
As of 2.2.3 this no longer works, the types are lost when consuming the store. If i understand correctly it's related to #2771 |
Hello There ! import { defineStore, storeToRefs } from "pinia"
export function defineComposable<Id extends string, SS extends () => any>(
id: Id,
storeSetup: SS,
): () => ReturnType<SS> {
const piniaStore = defineStore(id, storeSetup)
return () => {
const store = piniaStore()
const storeRefs = storeToRefs(store) as ReturnType<SS>
const composable = {} as ReturnType<SS>
for (const key in store) {
if (key in storeRefs) {
composable[key] = storeRefs[key]
}
else {
// @ts-expect-error Incorrect store typings
composable[key] = store[key]
}
}
return composable
}
} |
What problem is this solving
I actually came up with this because it is a bit annoying to add storeToRefs to each store if you want to destructuring
Proposed solution
I'm very new to this, it's the first time I do it, and while I was thinking how it could be implemented I found a repository where this function is better explained, I don't know if I can put the link?
The text was updated successfully, but these errors were encountered: