如何在Vue 3 SSR应用中,将vuex store集成到路由器中?
P粉883223328
P粉883223328 2023-08-25 10:09:45
[Vue.js讨论组]

我有一个使用SSR、Vue-Cli、Vuex和Typescript的Vue3项目。

在路由页面中,我需要将数据提交到Vuex Store中。在.vue文件中,我可以简单地使用this.$store,它在vuex.d.ts中进行了类型定义,如下:

this.$store.commit("setFoo", "Bar")

但是在没有this或vue实例的ts文件(router/index.ts)中,我该如何做到这一点呢?

我尝试导入store索引文件并进行提交:

import store from "@/store/index"

store.commit("setFoo", "Bar")

但是我得到了一个错误:

类型“() => Store<{ foo: string; }>”上不存在属性“commit”。ts(2339)

store文件(由于我正在运行SSR,所以store不能是单例):

import Vuex from "vuex"

export default function () {
  return new Vuex.Store({
    state: () => ({
      foo: "foo",
    }),
    mutations: {
      setFoo(state, payload) {
        state.foo = payload
      },
    },
  })
}

更新后的vuex 4 store文件:

import { createStore } from "vuex"

const store = {
  state: () => ({
    foo: "foo",
  })
}

export default function () {
  return createStore(store)
}

entry-client.js:

import createApp from "./main"

const { app, router } = createApp()

router.isReady().then(() => {
  app.mount("#app", true)
})

入口服务器.ts:

import createApp from "./main"

export default function () {
  const { app, router } = createApp()

  return {
    app,
    router,
  }
}

main.js:

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,
  }
}

路由器/index.ts:

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
}

包.json:

"scripts": {
  "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 --mode development --dest dist/server",
  "serve:client": "vue-cli-service serve",
  "serve:server": "node ./dist/server/server.js",
  "lint": "vue-cli-service lint"
},
"dependencies": {
  "@vue/server-renderer": "^3.2.4",
  "axios": "^0.21.1",
  "core-js": "^3.6.5",
  "express": "^4.17.1",
  "vue": "^3.0.0",
  "vue-axios": "^3.2.5",
  "vue-router": "^4.0.0-0",
  "vuex": "^4.0.0-0"
},
"devDependencies": {
  "@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",
  "node-sass": "^4.12.0",
  "prettier": "^2.2.1",
  "sass-loader": "^8.0.2",
  "typescript": "~4.1.5",
  "webpack-manifest-plugin": "^4.0.2",
  "webpack-node-externals": "^3.0.0"
}
P粉883223328
P粉883223328

全部回复(2)
P粉693126115

您的默认导出是一个函数

export default function () {

我认为您想要做的是这样的:

export default new Vuex.Store({...})

如果您想保持它作为一个函数,您也可以尝试 store().commit 但这样每次调用 store() 都会创建一个新的 Vuex 实例

P粉811349112

请注意,避免使用有状态的单例规则不仅适用于主应用实例和存储,还适用于路由器

您当前的Router/index.ts创建了有状态的单例。您需要创建一个“路由器工厂”函数,以便每个服务器请求都获得新的路由器实例。另一个好处是现在您可以将存储实例传递给它

Router/index.ts

  import { createRouter, createWebHistory, createMemoryHistory } from "vue-router"
  import axios from "axios"
  import MockAdapter from "axios-mock-adapter"
  import { routes } from "./routes"
  import { isSSR } from "@/helpers"

  const createHistory = isSSR()
    ? createMemoryHistory
    : createWebHistory

  export default function (store) {
    const router = createRouter({ 
      routes, 
      history: createHistory(process.env.BASE_URL)
    })

    router.beforeEach(async (to, from, next) => {
      // do stuff with store (store comes from argument)
    })
  
    return router
  }

请注意服务器和客户端捆绑包都应使用createSSRApp - 如果使用标准的createApp客户端的水合作用将无法正常工作

main.js

import { createSSRApp, 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 = createSSRApp(rootComponent)
  const store = createStore()
  const router = createRouter(store)

  app.use(VueAxios, axios)
  app.use(router)
  app.use(store)

  app.provide("axios", app.config.globalProperties.axios)

  return {
    app,
    router,
    store,
  }
}
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号