046Vue3的官方推荐的三个组件传值解决方案:props、pinia(状态管理)、provide和inject
创始人
2024-03-24 21:27:33
0

046Vue3的官方推荐的三个组件传值解决方案:props、pinia(状态管理)、provide和inject

  • 以下代码基于setup编写

props


props单向数据流

所有的 props 都遵循着单向绑定原则,props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递。这避免了子组件意外修改父组件的状态的情况,不然应用的数据流将很容易变得混乱而难以理解。
  • prop 被用于传入初始值;而子组件想在之后将其作为一个局部数据属性。在这种情况下,最好是新定义一个局部数据属性,从 props 上获取初始值即可:
const props = defineProps(['initialCounter'])// 计数器只是将 props.initialCounter 作为初始值
// 像下面这样做就使 prop 和后续更新无关了
const counter = ref(props.initialCounter)
  • 需要对传入的 prop 值做进一步的转换。在这种情况中,最好是基于该 prop 值定义一个计算属性:
const props = defineProps(['size'])// 该 prop 变更时计算属性也会自动更新
const normalizedSize = computed(() => props.size.trim().toLowerCase())

Prop 校验

defineProps({// 基础类型检查// (给出 `null` 和 `undefined` 值则会跳过任何类型检查)propA: Number,// 多种可能的类型propB: [String, Number],// 必传,且为 String 类型propC: {type: String,required: true},// Number 类型的默认值propD: {type: Number,default: 100},// 对象类型的默认值propE: {type: Object,// 对象或数组的默认值// 必须从一个工厂函数返回。// 该函数接收组件所接收到的原始 prop 作为参数。default(rawProps) {return { message: 'hello' }}},// 自定义类型校验函数propF: {validator(value) {// The value must match one of these stringsreturn ['success', 'warning', 'danger'].includes(value)}},// 函数类型的默认值propG: {type: Function,// 不像对象或数组的默认,这不是一个工厂函数。这会是一个用来作为默认值的函数default() {return 'Default function'}}
})

pinia(状态管理)

import { defineStore } from 'pinia'export const useTodos = defineStore('todos', {state: () => ({/** @type {{ text: string, id: number, isFinished: boolean }[]} */todos: [],/** @type {'all' | 'finished' | 'unfinished'} */filter: 'all',// 类型将自动推断为 numbernextId: 0,}),getters: {finishedTodos(state) {// 自动补全! ✨return state.todos.filter((todo) => todo.isFinished)},unfinishedTodos(state) {return state.todos.filter((todo) => !todo.isFinished)},/*** @returns {{ text: string, id: number, isFinished: boolean }[]}*/filteredTodos(state) {if (this.filter === 'finished') {// 调用其他带有自动补全的 getters ✨return this.finishedTodos} else if (this.filter === 'unfinished') {return this.unfinishedTodos}return this.todos},},actions: {// 接受任何数量的参数,返回一个 Promise 或不返回addTodo(text) {// 你可以直接变更该状态this.todos.push({ text, id: this.nextId++, isFinished: false })},},
})

pinia的封装与引入

import { toStr } from '@/utils/Json';
import { createPinia, type PiniaPluginContext } from 'pinia'; // 引入pinia
import { toRaw } from 'vue';
const pinia = createPinia(); // 创建// 定义缓存管理用的配置数据类型
interface IStorageOption {key: string;keeps: {sessions: string[];locals: string[];};
}
// 缓存配置数据
const storageOption: IStorageOption = {key: '__pinia__', //缓存名key的前置字符串keeps: {sessions: [], // 采用seesionStorage缓存的keylocals: ['model', 'model00411'], // 采用localStorage缓存的key},
};
// 储存pinia的值
function setStorage(key: string,val: any,storageType: Storage = localStorage
) {const obj = { v: val };console.log(666.789, key);storageType.setItem(storageOption.key + key, toStr(obj));
}
// 从缓存中获取pinia的值
function getStorage(key: string, storageType: Storage = localStorage) {const val = storageType.getItem(storageOption.key + key);const obj = val ? JSON.parse(val as string) : null;return obj?.v || null;
}
// 依据配置项综合处理缓存的读写
function doStorage(key: string,store: any,storageType: Storage = localStorage
) {const storageResult = getStorage(key, storageType);if (storageResult) {console.log(666.7007, '读取啦', storageResult, key, toRaw(store.$state));store.$patch(() => {store.$state = { ...storageResult };});}store.$subscribe(() => {console.log(666.7002, '更新啦', key, toRaw(store.$state));setStorage(key, toRaw(store.$state), storageType);});
}
// 处理pinia缓存需要的中间件
function useStorage() {return (ctx: PiniaPluginContext) => {const { store } = ctx;const sid = store.$id;if (storageOption.keeps.locals.includes(sid)) {doStorage(sid, store, localStorage);} else if (storageOption.keeps.sessions.includes(sid)) {doStorage(sid, store, sessionStorage);}};
}pinia.use(useStorage());export default pinia;

引入

import { createApp } from 'vue';
import App from './App.vue';
import pinia from './stores';const app = createApp(App);
app.use(pinia);
app.mount('#app');

项目中使用方法

import { defineStore } from 'pinia';// 默认的初始化数据引入
const modelStoreTmp = {type: 1,data: {val: 3,item: { a: 1, b: 2 },},
};export default defineStore('piniaName', {state: () => {return {modelStore: modelStoreTmp,};},actions: {},
});
  • 调用方法
import ModelStore from './store';
// 通过状态管理,得到一个ref的值
const modelStore = ModelStore().modelStore;

provide和inject

Provide (提供)

import { provide } from 'vue'provide(/* 注入名 */ 'message', /* 值 */ 'hello!')

Inject (注入)

import { inject } from 'vue'// 如果没有祖先组件提供 "message"
// `value` 会是 "这是默认值"
const message = inject('message', '这是默认值')

建议尽可能将任何对响应式状态的变更都保持在供给方组件中

import { provide, ref } from 'vue'const location = ref('North Pole')function updateLocation() {location.value = 'South Pole'
}provide('location', {location,updateLocation
})
  • 注入调用方式

三种方式的传值,按需使用

  • 父子组件使用props
  • 有层级关系的多个组件provide
  • 跨无关联组件使用pinia

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
苏州离哪个飞机场近(苏州离哪个... 本篇文章极速百科小编给大家谈谈苏州离哪个飞机场近,以及苏州离哪个飞机场近点对应的知识点,希望对各位有...
客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...