Vue 组件需要多次导入 Pinia store props 吗?
Do I need to import Pinia store props multiple times in a Vue component?
我正在处理我的第一个 Vue 项目。我习惯了 React 和 vanilla js,但只是想了解一下 Vue 中的一些概念。
特别是从 Pinia 商店导入状态和动作道具,并且似乎必须在单个 Vue 组件中多次导入这些道具(我不需要在 React 中做的事情)。
在这个例子中,我导入了一个简单的计数值和一个增量函数,并尝试在几个不同的地方使用它们:
<script setup>
// I import everything initially in setup, which works fine,
// and these props (currentCount and incrementCount)
// can be used in my template:
import { storeToRefs } from 'pinia';
import { useStore } from '@/stores/store';
const { currentCount } = storeToRefs(useStore());
const { incrementCount } = useStore();
</script>
<template>
<main>
Current count: {{ currentCount }}
<button @click="incrementCount">Increment</button>
</main>
</template>
<script>
// I can't use store values from setup here.
// This doesn't work:
// console.log(currentCount);
// I also can't import store values here.
// I get the following error:
// "getActivePinia was called with no active Pinia"
// const { currentCount } = storeToRefs(useStore());
export default {
mounted() {
// I have to import store values here for them to work:
const { currentCount } = storeToRefs(useStore());
console.log(currentCount);
},
watch: {
// weirdly, this reference to watching "currentCount" works:
currentCount() {
// I also have to import store values here for them to work:
const { currentCount } = storeToRefs(useStore());
console.log(currentCount);
},
},
};
</script>
如您所见,如果我想在我的模板、挂载和观察程序中使用存储值(我将使用 React 的 useEffect 挂钩),我总共必须导入存储道具 3 次.
这是正确/正常的吗?有没有更简单的方法来实现我正在做的事情,我只导入一次道具?我想确定我没有错过任何事情,也没有以不寻常的方式做某事。
感谢您的帮助和建议!
Pinia 的设计考虑到了构图 API。
所以它的预期用途是在 setup()
函数中,你只需要导入一次。
要在 setup()
函数之外使用它,您有两个主要途径:
- 在组件内部,您只需从
setup()
return 它就可以在任何 hook/method/getter 中使用它。作为 this.store
或传播:
import { useStore } from '@/store'
import { toRefs } from 'vue'
// or from '@vue/composition-api' in Vue2
export default {
setup: () => ({ ...toRefs(useStore()) })
}
/* this makes every state prop, getter or action directly available
on current component instance. In your case, `this.currentCount`.
Obviously, you can also make the entire store available as `this.someStore`:
setup: () => ({ someStore: useSomeStore() })
// now you can use `this.someStore` anywhere
*/
- 一种更通用的方法是从
main.(js|ts)
导出 pinia
实例(return 由 createPinia()
编辑),将其导入到您需要存储的位置,然后调用 useStore()
将 pinia 实例作为参数传递。
这可以在任何地方完成,甚至在组件之外。
通用示例:
import { pinia } from 'main.js'
import { useSomeStore } from '@/store'
const someStore = useSomeStore(pinia);
我可能还应该提到 pinia
提供的 mapState
助手。它允许您 select 仅暴露给当前实例的少数键。示例:
import { mapState } from 'pinia'
// ...
computed: {
...mapState(useSomeStore, [ 'currentCount'])
}
// Now `this.currentCount` is available
注意:mapState
的名字很奇怪,因为它允许您访问的不仅仅是 state
道具(还有 getters
和 actions
)。它被命名为 mapState
以匹配来自 vuex
.
的类似助手
一种更通用的方法是将您的商店添加为全局商店,使用 Vue2 中的插件注册 API:
import { useSomeStore } from '@/store';
import { createPinia } from 'pinia';
const pinia = createPinia();
const someStorePlugin = {
install(Vue, options) {
Vue.prototype.someStore = useSomeStore(options.pinia)
}
};
Vue.use(someStorePlugin, { pinia });
new Vue({ pinia });
在此之后,您的 Vue 实例的每个组件都将 this.someStore
可用,而无需导入它。
注意:我还没有测试过在全局变量中添加商店(我绝对反对它——你应该避免使用全局变量),但我希望它能起作用。
如果您想将 pinia
商店与选项 API 结合使用,一种方法是使用选项中的 setup()
函数来调用 useStore
:
<script>
import { useStore } from '@/stores/store';
export default {
setup() {
const store = useStore();
return {store}
},
watch: {
store.currentBrightness(newVal, oldVal){
// your code
}
},
methods: {
// inside methods use this.store
},
mounted() {
console.log(this.store.currentCount);
}
}
</script>
有些人可能认为这是组合和选项的不合需要的组合 API,但在我看来,这是 pinia 商店的一个很好的解决方案。
我正在处理我的第一个 Vue 项目。我习惯了 React 和 vanilla js,但只是想了解一下 Vue 中的一些概念。
特别是从 Pinia 商店导入状态和动作道具,并且似乎必须在单个 Vue 组件中多次导入这些道具(我不需要在 React 中做的事情)。
在这个例子中,我导入了一个简单的计数值和一个增量函数,并尝试在几个不同的地方使用它们:
<script setup>
// I import everything initially in setup, which works fine,
// and these props (currentCount and incrementCount)
// can be used in my template:
import { storeToRefs } from 'pinia';
import { useStore } from '@/stores/store';
const { currentCount } = storeToRefs(useStore());
const { incrementCount } = useStore();
</script>
<template>
<main>
Current count: {{ currentCount }}
<button @click="incrementCount">Increment</button>
</main>
</template>
<script>
// I can't use store values from setup here.
// This doesn't work:
// console.log(currentCount);
// I also can't import store values here.
// I get the following error:
// "getActivePinia was called with no active Pinia"
// const { currentCount } = storeToRefs(useStore());
export default {
mounted() {
// I have to import store values here for them to work:
const { currentCount } = storeToRefs(useStore());
console.log(currentCount);
},
watch: {
// weirdly, this reference to watching "currentCount" works:
currentCount() {
// I also have to import store values here for them to work:
const { currentCount } = storeToRefs(useStore());
console.log(currentCount);
},
},
};
</script>
如您所见,如果我想在我的模板、挂载和观察程序中使用存储值(我将使用 React 的 useEffect 挂钩),我总共必须导入存储道具 3 次.
这是正确/正常的吗?有没有更简单的方法来实现我正在做的事情,我只导入一次道具?我想确定我没有错过任何事情,也没有以不寻常的方式做某事。
感谢您的帮助和建议!
Pinia 的设计考虑到了构图 API。
所以它的预期用途是在 setup()
函数中,你只需要导入一次。
要在 setup()
函数之外使用它,您有两个主要途径:
- 在组件内部,您只需从
setup()
return 它就可以在任何 hook/method/getter 中使用它。作为this.store
或传播:
import { useStore } from '@/store'
import { toRefs } from 'vue'
// or from '@vue/composition-api' in Vue2
export default {
setup: () => ({ ...toRefs(useStore()) })
}
/* this makes every state prop, getter or action directly available
on current component instance. In your case, `this.currentCount`.
Obviously, you can also make the entire store available as `this.someStore`:
setup: () => ({ someStore: useSomeStore() })
// now you can use `this.someStore` anywhere
*/
- 一种更通用的方法是从
main.(js|ts)
导出pinia
实例(return 由createPinia()
编辑),将其导入到您需要存储的位置,然后调用useStore()
将 pinia 实例作为参数传递。
这可以在任何地方完成,甚至在组件之外。
通用示例:
import { pinia } from 'main.js'
import { useSomeStore } from '@/store'
const someStore = useSomeStore(pinia);
我可能还应该提到 pinia
提供的 mapState
助手。它允许您 select 仅暴露给当前实例的少数键。示例:
import { mapState } from 'pinia'
// ...
computed: {
...mapState(useSomeStore, [ 'currentCount'])
}
// Now `this.currentCount` is available
注意:mapState
的名字很奇怪,因为它允许您访问的不仅仅是 state
道具(还有 getters
和 actions
)。它被命名为 mapState
以匹配来自 vuex
.
一种更通用的方法是将您的商店添加为全局商店,使用 Vue2 中的插件注册 API:
import { useSomeStore } from '@/store';
import { createPinia } from 'pinia';
const pinia = createPinia();
const someStorePlugin = {
install(Vue, options) {
Vue.prototype.someStore = useSomeStore(options.pinia)
}
};
Vue.use(someStorePlugin, { pinia });
new Vue({ pinia });
在此之后,您的 Vue 实例的每个组件都将 this.someStore
可用,而无需导入它。
注意:我还没有测试过在全局变量中添加商店(我绝对反对它——你应该避免使用全局变量),但我希望它能起作用。
如果您想将 pinia
商店与选项 API 结合使用,一种方法是使用选项中的 setup()
函数来调用 useStore
:
<script>
import { useStore } from '@/stores/store';
export default {
setup() {
const store = useStore();
return {store}
},
watch: {
store.currentBrightness(newVal, oldVal){
// your code
}
},
methods: {
// inside methods use this.store
},
mounted() {
console.log(this.store.currentCount);
}
}
</script>
有些人可能认为这是组合和选项的不合需要的组合 API,但在我看来,这是 pinia 商店的一个很好的解决方案。