如何在Vue 3 SSR应用中,将vuex store集成到路由器中?
P粉883223328
2023-08-25 10:09:45
<p>我有一个使用SSR、Vue-Cli、Vuex和Typescript的Vue3项目。</p>
<p>在路由页面中,我需要将数据提交到Vuex Store中。在.vue文件中,我可以简单地使用this.$store,它在vuex.d.ts中进行了类型定义,如下:</p>
<pre class="brush:php;toolbar:false;">this.$store.commit("setFoo", "Bar")</pre>
<p>但是在没有this或vue实例的ts文件(router/index.ts)中,我该如何做到这一点呢?</p>
<p>我尝试导入store索引文件并进行提交:</p>
<pre class="brush:php;toolbar:false;">import store from "@/store/index"
store.commit("setFoo", "Bar")</pre>
<p>但是我得到了一个错误:</p>
<blockquote>
<p>类型“() => Store<{ foo: string; }>”上不存在属性“commit”。ts(2339)</p>
</blockquote>
<p>store文件(由于我正在运行SSR,所以store不能是单例):</p>
<pre class="brush:php;toolbar:false;">import Vuex from "vuex"
export default function () {
return new Vuex.Store({
state: () => ({
foo: "foo",
}),
mutations: {
setFoo(state, payload) {
state.foo = payload
},
},
})
}</pre>
<p>更新后的vuex 4 store文件:</p>
<pre class="brush:php;toolbar:false;">import { createStore } from "vuex"
const store = {
state: () => ({
foo: "foo",
})
}
export default function () {
return createStore(store)
}</pre>
<p>entry-client.js:</p>
<pre class="brush:php;toolbar:false;">import createApp from "./main"
const { app, router } = createApp()
router.isReady().then(() => {
app.mount("#app", true)
})</pre>
<p>入口服务器.ts:</p>
<pre class="brush:php;toolbar:false;">import createApp from "./main"
export default function () {
const { app, router } = createApp()
return {
app,
router,
}
}</pre>
<p>main.js:</p>
<pre class="brush:php;toolbar:false;">import { createSSRApp, createApp, h } from "vue"
import { isSSR } from "@/helpers"
import createRouter from "@/router"
import createStore from "@/store"
import axios from "axios"
import VueAxios from "vue-axios"
import App from "@/App.vue"
export default function () {
const rootComponent = {
render: () => h(App),
components: { App },
}
const app = (isSSR() ? createSSRApp : createApp)(rootComponent)
const router = createRouter()
const store = createStore()
app.use(VueAxios, axios)
app.use(router)
app.use(store)
app.provide("axios", app.config.globalProperties.axios)
return {
app,
router,
store,
}
}</pre>
<p>路由器/index.ts:</p>
<pre class="brush:php;toolbar:false;">import { createRouter, createWebHistory, createMemoryHistory } from "vue-router"
import store from "@/store/index"
import axios from "axios"
import MockAdapter from "axios-mock-adapter"
import { routes } from "./routes"
import { isSSR } from "@/helpers"
const history = isSSR()
? createMemoryHistory()
: createWebHistory(process.env.BASE_URL)
const router = createRouter({ routes, history })
router.beforeEach(async (to, from, next) => {
// do stuff with store
})
export default function () {
return router
}</前>
<p>包.json:</p>
<pre class="brush:php;toolbar:false;">"脚本": {
"build:all": "npm run build:client && npm run build:server",
"build:client": "vue-cli-service build --dest dist/client",
"build:server": "export SSR=1 || set SSR=1&& vue-cli-service build --dest dist/server",
"build:server:dev": "export SSR=1 || set SSR=1&& vue-cli-service build --modedevelopment --dest dist/server",
"serve:client": "vue-cli-service 服务",
“服务:服务器”:“节点./dist/server/server.js”,
"lint": "vue-cli-service lint"
},
“依赖项”:{
"@vue/server-renderer": "^3.2.4",
"axios": "^0.21.1",
"core-js": "^3.6.5",
"快递": "^4.17.1",
"vue": "^3.0.0",
"vue-axios": "^3.2.5",
"vue-router": "^4.0.0-0",
“vuex”:“^4.0.0-0”
},
“开发依赖项”:{
"@typescript-eslint/eslint-plugin": "^4.18.0",
"@typescript-eslint/parser": "^4.18.0",
"@vue/cli-plugin-babel": "^5.0.0-beta.3",
"@vue/cli-plugin-eslint": "^5.0.0-beta.3",
"@vue/cli-plugin-router": "^5.0.0-beta.3",
"@vue/cli-plugin-typescript": "^5.0.0-beta.3",
"@vue/cli-plugin-vuex": "^5.0.0-beta.3",
"@vue/cli-service": "^5.0.0-beta.3",
"@vue/compiler-sfc": "^3.0.0",
"@vue/eslint-config-prettier": "^6.0.0",
"@vue/eslint-config-typescript": "^7.0.0",
"axios-mock-adapter": "^1.20.0",
"eslint": "^7.20.0",
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-vue": "^7.6.0",
“节点-sass”:“^4.12.0”,
"更漂亮": "^2.2.1",
"sass-loader": "^8.0.2",
“打字稿”:“~4.1.5”,
"webpack-manifest-plugin": "^4.0.2",
“webpack-node-externals”:“^3.0.0”
}</pre>
您的默认导出是一个函数
export default function () {
我认为您想要做的是这样的:
export default new Vuex.Store({...})
如果您想保持它作为一个函数,您也可以尝试
store().commit
但这样每次调用 store() 都会创建一个新的 Vuex 实例请注意,避免使用有状态的单例规则不仅适用于主应用实例和存储,还适用于路由器
您当前的
Router/index.ts
创建了有状态的单例。您需要创建一个“路由器工厂”函数,以便每个服务器请求都获得新的路由器实例。另一个好处是现在您可以将存储实例传递给它Router/index.ts
请注意,服务器和客户端捆绑包都应使用
createSSRApp
- 如果使用标准的createApp
,客户端的水合作用将无法正常工作main.js