再vue3.0之后,推出了组合式api以及新的响应式。使状态管理可不必再用vuex实现,就有点借鉴react-redux的状态管理了。接下来一 一介绍
常规vuex
// 这里store创建挂载就不讲了,cli创建就会有,只讲再.vue文件中使用,大致与2.x类似
// vue2.x中vuex使用参考:https://blog.csdn.net/HockJerry/article/details/113977151
import { ref } from "vue";
import { useStore } from "vuex";
export default {
setup() {
const store = useStore()
const state = store.state
function addNum () {
// state
// console.log(state.num)
// mutations
// store.commit("addNum",{num:1})
// store.commit({type:"addNum",num:1})
// actions
// store.dispatch("add",{num:10})
// store.dispatch({type:"add",num:10})
// getters
// num.value= store.getters.getNum
}
return {
state,
addNum
}
}
}
使用provide,inject,localStorage
这里provide和inject如果不理解可以去vue.js官网,看一会就懂了。
实现原理:
因为vue都是挂载在App下面的,所以在最上层provide,在下面的所有组件都可以通过inject获取到,
但是这样刷新的话就会与vuex一样状态初始化,所以借用localStorage作为数据存储中心实现永久储存。
创建actions
// createStore/actions.js
function setAge (state) {
return (age) => {
state.user.age += age
}
}
function addNum (state) {
return (count) => {
state.count += count
}
}
export default function setAction (state) {
return {
add: addNum(state),
setAge: setAge(state)
}
}
创建localStorage储存机制
这里借用watch来同步更新state和localStorage的数据,使用的时候可以去查看浏览器的localStorage更直观些,不会查看以前也写过
// createStore/save.js
import { readonly, watch, toRaw } from 'vue'
export default function createStore (state, key = 'default') {
const STORAGE_KEY = 'vue3' // 这是所有数据储存的标记,看自己命名
// 每次执行都会先去取一次,这样刷新就不会丢失数据
Object.entries(getItem(key)).forEach(([key, value]) => {
state[key] = value
})
function setItem (state, keys) {
const stateRow = getItem()
stateRow[keys] = state
const stateStr = JSON.stringify(stateRow)
localStorage.setItem(STORAGE_KEY, stateStr)
}
function getItem (keys) {
const stateStr = localStorage.getItem(STORAGE_KEY) || '{}'
const stateRow = JSON.parse(stateStr) || {}
return keys ? stateRow[keys] || {} : stateRow
}
// 这里的watch不懂的可以在前面的文章里看
watch(() => state, () => {
const stateRow = toRaw(state) // 这里的state还具有响应性,要用toRaw去掉响应性
setItem(stateRow, key)
}, { deep: true })
// 这里要用到readOnly,因为state是响应式的,所以外部不能随意更改只能通过定义的actions更改
return readonly(state)
}
定义state并组合
数据多的话也可以把定义state这一块单独拿出来,再引入合并
// createStore/index.js
import { reactive, readonly } from 'vue'
import setAction from './actions'
import createStore from './save'
export function doUser () {
const state = reactive({
user: {
name: 'jerry',
age: 18
},
count: 0
})
// actions 也要用readonly,不能更改
return {
state: createStore(state, 'hospital'), // 这里创建为hospital模块,也可以按照index.js多创几个
actions: readonly(setAction(state))
}
}
在App.vue中注入
<template>
<div id="nav">
<div>
{{state.user.name}}--{{state.user.age}}
</div>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
</template>
<script>
// 在最上层注入,里面的所有子组件就可通过inject获取
import { doUser } from './creatStore'
import { provide } from 'vue'
export default {
setup () {
const { state, actions } = doUser()
provide('hospital', { state, actions }) // 第一个参数是注入名(键名),第二个参数是值
return {
state
}
}
}
</script>
在Home.vue中inject获取
在这里点,App.vue的数据也会跟着变,刷新也不会丢失。
需要在actions添加方法,手动清除state的数据。或者直接浏览器清除localStorage(你肯定会的)
<template>
<div class="home">
<button type="button" class="" @click="setAge(1)">click</button>
<p>{{state.user.name}}--{{state.user.age}}</p>
</div>
</template>
<script>
import { inject } from 'vue'
export default {
name: 'Home',
setup () {
const { state, actions } = inject('hospital')
const setAge = actions.setAge
return {
state,
setAge
}
}
}
</script>
这就是通过provide,inject,localStorage实现全局状态管理。
下篇文章改动下,不用provide,inject实现。
顺便把文件夹贴出来,要不然到处引入怕混乱: