如何在 Vue 3 s-s-r 应用程序的路由器中使用 vuex 商店?
Posted
技术标签:
【中文标题】如何在 Vue 3 s-s-r 应用程序的路由器中使用 vuex 商店?【英文标题】:How do I use vuex store in the router in Vue 3 s-s-r app? 【发布时间】:2021-10-29 18:31:59 【问题描述】:我有一个带有 s-s-r、Vue-Cli、Vuex 和 Typescript 的 Vue3 项目。
在路由器页面中,我需要将数据提交到 Vuex Store。在 .vue 文件中,我只需使用在 vuex.d.ts 中输入的 this.$store,例如:
this.$store.commit("setFoo", "Bar")
但是我如何从没有 this 或 vue 实例的 ts 文件(router/index.ts)中做到这一点。
我已尝试导入存储索引文件并提交:
import store from "@/store/index"
store.commit("setFoo", "Bar")
但我得到一个错误
类型'() => Store'.ts(2339)
存储文件(因为我正在运行 s-s-r,所以存储不能是单例):
import Vuex from "vuex"
export default function ()
return new Vuex.Store(
state: () => (
foo: "foo",
),
mutations:
setFoo(state, payload)
state.foo = payload
,
,
)
更新了 vuex 4 的存储文件:
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 creates-s-rApp, createApp, h from "vue"
import iss-s-r 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 = (iss-s-r() ? creates-s-rApp : 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 iss-s-r from "@/helpers"
const history = iss-s-r()
? 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 s-s-r=1 || set s-s-r=1&& vue-cli-service build --dest dist/server",
"build:server:dev": "export s-s-r=1 || set s-s-r=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"
【问题讨论】:
请分享 package.json 文件 导入的不是store,而是store factory。调用它。 在路由器页面我需要提交数据 ...你说的路由器页面是什么意思?请添加更多代码... @EstusFlask 你能举个例子吗? @MichalLevý 我现在添加了更多代码 【参考方案1】:请注意,Avoid Stateful Singletons 规则不仅适用于主应用实例和商店,还适用于 also to a router
您当前的 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 iss-s-r from "@/helpers"
const createHistory = iss-s-r()
? 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
注意both server and client bundle should use creates-s-rApp
- 如果你使用标准的createApp
,client side hydration 将不起作用
Vue 提供了一个
creates-s-rApp
方法用于客户端代码,告诉 Vue 水合现有的静态 html,而不是重新创建所有 DOM 元素
main.js
import creates-s-rApp, h from "vue"
import iss-s-r 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 = creates-s-rApp(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,
【讨论】:
除此之外,我同意 Boussadjra Brahim - 如果您使用 Vuex 4new Vuex.Store
将不起作用,您需要使用 new api
看起来很有希望,我会尝试并接受它,谢谢!
@Per 我刚刚编辑了我的答案以解决另一个问题(在客户端上使用 createApp
而不是 creates-s-rApp
)【参考方案2】:
您的默认导出是一个函数
export default function ()
我想你想这样做:
export default new Vuex.Store(...)
如果您想将其保留为函数,您也可以尝试store().commit
,但这只会在您每次调用 store() 时创建一个新的 Vuex 实例
【讨论】:
因为我在运行 s-s-r,所以商店不能是单身 我想我必须像这样创建它,以免 s-s-r 产生内存问题。但是,如果我运行 store().commit 它可以工作,但正如你所说,它可能会创建一个新商店。必须有一种方法可以使用在 entry-client 中创建的那个?以上是关于如何在 Vue 3 s-s-r 应用程序的路由器中使用 vuex 商店?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 laravel 应用程序中为单个 vue 组件实现 s-s-r?
Vue.js 3 s-s-r - 客户端水合期间缺少模板或渲染功能
Vue 3 中的 s-s-r 和 keep-alive 问题:动态组件