该系列是为了让看过Vue官方文件或学过Vue但是却不知道怎麽下手去重构现在有的网站而去规画的系列文章,在这边整理了许多我自己使用Vue重构很多网站的经验分享给读者们。
我们在Vue要使用跨多个 component 做资料传递沟通的时候除了 Vuex 以外,在 Vue3 的时候我们有多了其他选择,那就是 Provide / inject 。
我们可以看到官网上面的这张图就完整的表达 Provide / inject 的使用概念,你可以在父层使用provide来提供资料,然後再子 component 透过 inject 来使用这些资料,无论你的 component 结构有多深,你的父层都可以为你所有底下的所有的 component 去直接 inject。
我们来看看如何实作,先来看看资料夹结构,其他资料夹等我就先不放上来了
|-- src
|-- App.vue // 最上层的component
|-- main.js // 进入点
|-- components
| |-- Content.vue // 一般的UI component
|-- store
| |-- index.js // 不是Vuex,是要使用 Composition API 存放资料的地方
|-- views
|-- Home.vue // 首页的页面component
首先我们先来定义 store/index.js
import { reactive, readonly } from "vue";
const state = reactive({
count: 0,
});
export default {
state: readonly(state),
};
在这边你会看到我透过 vue3 的reactive
去定义我的资料,透过 vue 的方法可以确保我的资料被更动的时候可以被更新,当然你可以用ref
,就依照你的需求来决定,最後我在 export 的时候用了 readonly
函数包起来,就是要避免外面 inject
的时候不小心改到 state 的资料,至於要怎麽改资料我们等等来说,我们先来看要怎麽在component 去使用。
App.vue
<script>
import { provide } from "vue";
import store from "@/store";
import Home from "@/views/Home.vue";
export default {
components: {
Home,
},
setup() {
provide("mapStore", store);
},
};
</script>
我在 setup 里面将我们 provide
命名为 mapStore
( 借镜一下 Vuex 的命名,这样从 Vuex 转换过来也会比较亲切 ) ,然後把我刚刚定义好的资料给载入进来,就这麽简单。
Content.vue
<script>
import { inject, toRefs } from "vue";
export default {
setup() {
const mapStore = inject("mapStore");
const { state } = mapStore;
return {
...toRefs(state),
};
},
};
</script>
<template>
<div class="content">
<h1>count: {{ count }}</h1>
<button>add</button>
<button>remove</button>
</div>
</template>
这边透过 inject 的方式把我的 mapStore 给注入进来,接下来我就可以直接取得我定义好的state 资料,然後丢到我的template上,不过这边要注意我使用了toRefs 去做包我的 state,为什麽不直接把 state 丢出去呢?
原因是因为透过 reactive 包装的资料,是透过解构的方式取出的话,会失去它的连动特性,所以这个时候在需要透过 toRefs 的包装,来让它维持资料的连动,最後把我定义好的 count 这个资料放到画面上
toRefs 详情可以参考文件 https://v3.cn.vuejs.org/api/refs-api.html#torefs
现在的画面长这样
假设今天我直接增加一个 function去修改我拿到的count的话
<script>
import { inject, toRefs } from "vue";
export default {
setup() {
const mapStore = inject("mapStore");
const { state } = mapStore;
const headleClick = () => {
state.count++;
};
return {
...toRefs(state),
headleClick,
};
},
};
</script>
<template>
<div class="content">
<h1>count: {{ count }}</h1>
<button @click="headleClick">add</button>
<button>remove</button>
</div>
</template>
你 click 它 log 会跳出说这个资料它是唯独的,不可以修改
这是因为我们在 store/index.js 里面透过readonly回传的,所以我们不能这样修改,readonly的好处就是要避免开发者直接修改资料,所以我们应该另外去定义可以修改的资料的 function,让资料归资料,修改交给其他方法去做。
我们在 store/index.is 上面新增了add 跟 remove 的两个 functino
import { reactive, readonly } from "vue";
const state = reactive({
count: 0,
});
const addCount = () => {
state.count++;
};
const removeCount = () => {
state.count--;
};
export default {
state: readonly(state),
addCount,
removeCount,
};
然後把 function 取出来就可以挂在我们的 button,就可以成功的修改资料
<script>
import { inject, toRefs } from "vue";
export default {
setup() {
const mapStore = inject("mapStore");
const { state, addCount, removeCount } = mapStore;
return {
...toRefs(state),
addCount,
removeCount,
};
},
};
</script>
<template>
<div class="content">
<h1>count: {{ count }}</h1>
<button @click="addCount">add</button>
<button @click="removeCount">remove</button>
</div>
</template>
透过这样的方式我们就可以不需要透过 Vuex 的方式来共用资料,你可能会问说如果要像 actions 一样处理非同步的 API 要怎麽办 ?
一样我们可以把非同步给放到store/index.js里面,这边我就写一个大概的示范
const fetchUserData = async () => {
try {
const res = await axios.get("https://www.api.com/api/user");
const { name, age, address } = res.data;
state.name = name;
state.age = age;
state.address = address;
} catch (error) {
state.errorMessage = "This user is not found!";
}
};
这边其实我们就把 store/index.js 给当成 Vuex 使用那样来使用,有 state、actions/mutations,如果你想要有getter 的功能的话也可以使用 computed 来替代达成。
import { computed, reactive, readonly } from "vue";
const userInfo = computed(()=> {
return `Info: ${state.name}, ${state.age}, ${state.address}`
})
export default {
state: readonly(state),
addCount,
removeCount,
userInfo
};
这也是很多人在说为什麽使用 Vue3 的时候可能不需要在使用 Vuex 的原因,因为我们就可以利用Provide / inject来达成使用Vuex管理资料的作法。
我自己的使用下来归纳几个想法
最後杀鸡焉用牛刀,我们不管用哪个都没有对错,就只有适不适合而已,今天在这边介绍了如何使用 Provide / inject,下一篇我们来谈谈 Vue3 使用 Vuex 的一些进阶的用法。
Ps. 购买的时候请登入或注册该平台的会员,然後再使用下面连结进入网站点击「立即购课」,这样才可以让我获得更多的课程分润,还可以帮助我完成更多丰富的内容给各位。
我有开设了一堂专门针对Vue3从零开始教学的课程,如果你觉得不错的话,可以购买我课程来学习
https://hiskio.com/bundles/9WwPNYRpz?s=tc
那如果对於JS基础不熟的朋友,我也有开设JS的入门课程,可以参考这个课程
https://hiskio.com/bundles/b9Rovqy7z?s=tc
Mike 的 Youtube 频道
Mike的medium
MIke 的官方 line 帐号,好友搜寻 @mike_cheng
昨天已经把大部分的 GUI 弄完了,之前也已经写好了服务器的程序,今天我们把两边拼起来吧! 搬移 s...
在 Composition API 当中我们可以将响应式资料和相关业务逻辑结合到一起,是因为 Vue...
从一开始接触Django到现在也一个月了 来简述跟总结一下自己认知到的技能 Django 网址传进来...
最近用Typescript开发专案,小弟用的是Windows10笔电 遇到一个小烦恼,那就是每次打开...
您所使用的Windows 10是否经常崩溃?您是否在Windows 10中收到档案丢失或损坏的错误?...