<section id="nice" data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding: 0 10px; line-height: 1.6; word-spacing: 0px; word-break: break-word; word-wrap: break-word; text-align: left; font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif; font-size: 15px; letter-spacing: 0.05em; color: #595959;"><h1 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; font-size: 24px; margin: 1.2em 0 1em; padding: 0; font-weight: bold; color: #773098;"><span class="prefix" style="display: none;"></span><span class="content">React 有Provider-Constmer+Hook模式,Vue 3.0 也要!</span><span class="suffix"></span></h1>
<figure data-tool="mdnice编辑器" style="margin: 0; margin-top: 10px; margin-bottom: 10px; display: flex; flex-direction: column; justify-content: center; align-items: center;"></figure>
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; min-height: 32px; line-height: 28px; border-bottom: solid 1px #000000; color: #773098; display: inline-block; border-bottom-width: 1px; border-bottom-style: solid; border-color: #773098; padding-top: 5px; padding-right: 0.5em; padding-left: 0.5em; margin-bottom: -3px; font-size: 22px; margin: 1em auto; padding: 0.5em 0; text-align: center; width: 85%; font-weight: bold; display: flex; flex-direction: column; justify-content: center;"><span class="prefix" style="display: none;"></span><span class="content">前言</span><span class="suffix"></span></h2>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">相熟React的小伙伴都晓得,随着React hook的推出,React呈现了一种新型的状态治理形式 Provider-Consumer模式,能够说是真香正告。</p>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">随着Vue3.0的公布,提供了咱们属于Vue的 Hook+provider-inject的新型状态管理工具。 本篇文章将以概念+案例联合的模式为大家解说该模式的用法和长处。</p>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">文章目录:</p>
<ol data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: decimal;">
<li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">引出问题,这种模式解决了什么问题?(长处)</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">如何应用,代码解构,我的项目案例。(以代码为主)</section></li></ol>
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; min-height: 32px; line-height: 28px; border-bottom: solid 1px #000000; color: #773098; display: inline-block; border-bottom-width: 1px; border-bottom-style: solid; border-color: #773098; padding-top: 5px; padding-right: 0.5em; padding-left: 0.5em; margin-bottom: -3px; font-size: 22px; margin: 1em auto; padding: 0.5em 0; text-align: center; width: 85%; font-weight: bold; display: flex; flex-direction: column; justify-content: center;"><span class="prefix" style="display: none;"></span><span class="content">1. 引出问题</span><span class="suffix"></span></h2>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">首先我以自问自答的形式来引出一些问题和以往的解决方案。带着问题学习是一种很好的学习办法吧。(我要我感觉)</p>
<ol data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: decimal;">
<li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">在vue中,兄弟组件、祖孙组件如何通信?</section></li></ol>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">看到第一个问你,你是不是嘴角微微上扬,45度角俯视天空,微撩刘海(如果你不是秃头的话????),感觉这很easy</p>
<ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;">
<li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">Vuex;不论多简单的组件通信,Vuex好像一键搞定。然而,Vuex作为一个状态治理的重型利器,在面对大量的须要多组件共享的数据,显然是杀鸡用????????啊。况且在一个小型的Vue我的项目中,根本都不必Vuex,太重了不是么?</p>
</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">EventBus;这种办法罕用于兄弟级别的组件通信。弊病也是非常明显;</p>
</section></li></ul>
<ol data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: decimal;">
<li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">EventBus不会随着组件的销毁而主动销毁,须要咱们手销毁;</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">挂在到全局;</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">留神:肯定要记得销毁,否则会呈现bug;</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">事件产生者只能单向播送,无奈取得接收者对事件的处理结果;</section></li></ol>
<ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;">
<li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">其余(attrs,provide-inject(vue2.x的,本地缓存,url传参)。这些办法都不太罕用,尽管能勉强解决跨组件通信,但都是有种本末倒置的感觉。(我要我感觉????);</section></li></ul>
<ol start="2" data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: decimal;">
<li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">在Vue2.x中,如何进行逻辑复用?</section></li></ol>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">举个栗子:在后盾治理我的项目中,多个菜单(组件)同时用到一堆数据,进行花色出现,有列表展现、有饼图占比、有折线图趋势、有热力求阐明频次等等,这些组件应用的是雷同的一些数据和数据处理逻辑(增删改查);如果在每个组件只都写一套这类的解决逻辑,显然是不合乎程序员的终极目标(偷懒????);
以往的解决方案:</p>
<ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;">
<li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">Mixins</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">高阶组件 (Higher-order Components, aka HOCs)</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">Renderless Components (基于 scoped slots / 作用域插槽封装逻辑的组件)</section></li></ul>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">其实下面在写业务代码的时候,也就mixin罕用。高阶组件和Renderless Components更多的是封装组件的时候用到的。它们存在的毛病:</p>
<ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;">
<li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">模版中的数据起源不清晰</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">命名空间抵触。</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">须要额定的组件实例嵌套来封装逻辑(性能问题);</section></li></ul>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">那么Vue将如何解决以上这些问题呢。</p>
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; min-height: 32px; line-height: 28px; border-bottom: solid 1px #000000; color: #773098; display: inline-block; border-bottom-width: 1px; border-bottom-style: solid; border-color: #773098; padding-top: 5px; padding-right: 0.5em; padding-left: 0.5em; margin-bottom: -3px; font-size: 22px; margin: 1em auto; padding: 0.5em 0; text-align: center; width: 85%; font-weight: bold; display: flex; flex-direction: column; justify-content: center;"><span class="prefix" style="display: none;"></span><span class="content">概念</span><span class="suffix"></span></h2>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">context</p>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">咱们要利用 provide+inject+hook 创立一个上下文对象,而且对外裸露 供应者(通常在组件树中上层的地位和消费者(inject)),只有在下层组件应用provide,在上下文以内的所有子组件,通过inject都可能接见这个上下文环境以内的数据,而且不用经由过程props。也就是提供了一个汇合治理并具备响应式的对象,并限度了这个对象可接见的局限,在局限内的子组件都能猎取到她外部的值。</p>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">provide+inject</p>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">在下层组件通过 provide 提供一些变量,在子组件中能够通过 inject 来拿到</p>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">provide用法:</p>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">provide承受两个参数,第一个参数是provide惟一名称,最好用Symbol,防止反复。第二个参数是你要裸露的数据</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;"> provide(ThemeSymbol, data)
</pre>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">inject 用法:</p>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">inject 接管两个参数,第一个参数是provide名称,也就是ThemeSymbol,第二个参数是provide裸露进去的数据,也就是data。</p>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">Hook</p>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">Vue3.0的composition api和setup提供了Vue具备Hook的能力。而Hook的存在能够让你在组件之外封装公共办法,达到逻辑复用。所以,咱们能够在.vue组件外自定义Hook,创立context;</p>
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; min-height: 32px; line-height: 28px; border-bottom: solid 1px #000000; color: #773098; display: inline-block; border-bottom-width: 1px; border-bottom-style: solid; border-color: #773098; padding-top: 5px; padding-right: 0.5em; padding-left: 0.5em; margin-bottom: -3px; font-size: 22px; margin: 1em auto; padding: 0.5em 0; text-align: center; width: 85%; font-weight: bold; display: flex; flex-direction: column; justify-content: center;"><span class="prefix" style="display: none;"></span><span class="content">文件目录解构</span><span class="suffix"></span></h2>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">依据下面的观点和功能,分析一下要实现的步骤:</p>
<ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;">
<li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">建设一个公共context,封装自定义hook</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">provide供给数据</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">inject注入数据</section></li></ul>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">这里的文件结构:</p>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">context</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">├─context // context的文件夹
</pre>
├─index.js // context根组件,对立引入各个模块的context,并对立裸露
│─home // 以模块名称命名,一个模块一个context
│─index.js
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">View</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;"> ├─View
</pre>
├─Home
├─index.vue // 根组件,在这层注入inject
├─xxx.vue // 其余组件 消费者地点的层级
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; min-height: 32px; line-height: 28px; border-bottom: solid 1px #000000; color: #773098; display: inline-block; border-bottom-width: 1px; border-bottom-style: solid; border-color: #773098; padding-top: 5px; padding-right: 0.5em; padding-left: 0.5em; margin-bottom: -3px; font-size: 22px; margin: 1em auto; padding: 0.5em 0; text-align: center; width: 85%; font-weight: bold; display: flex; flex-direction: column; justify-content: center;"><span class="prefix" style="display: none;"></span><span class="content">用法</span><span class="suffix"></span></h2>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">为了不便解读,我这里以Todolist我的项目为例;</p>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">源码: https://github.com/961998264/...</p>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">我的项目介绍:</p>
<ol data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: decimal;">
<li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">新增待办事件</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">编辑待办事件</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">删除待办事件</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; margin: 10px 0;">查看待办事件</section></li></ol>
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; font-size: 20px; margin: 1.2em 0 1em; padding: 0; font-weight: bold; color: #773098;"><span class="prefix" style="display: none;"></span><span class="content">1. 建设一个上下文context</span><span class="suffix" style="display: none;"></span></h3>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">// 引入 composition api
</pre>
import { provide, ref, Ref, inject, computed, } from <span class="hljs-string" style="color: #D69D85; line-height: 26px;">'vue'</span>
// provide命名
<span class="hljs-built_in" style="color: #4EC9B0; line-height: 26px;">export</span> const listymbol = Symbol()
// 自定义hook,借用React hook命名规范,以use结尾
<span class="hljs-built_in" style="color: #4EC9B0; line-height: 26px;">export</span> const useProvide = () => {
const list = ref([])
// 获取list
const getList = async <span class="hljs-function" style="color: #DCDCDC; line-height: 26px;"><span class="hljs-title" style="color: #DCDCDC; line-height: 26px;">function</span></span> () { ... }
// 新增list
const addList = (item) => { ... }
// 删除事件
const delList = (id) => { ... },
...
// provide 裸露数据
provide(listymbol, {
list,
getList,
addList,
delList
})
}
<h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; font-size: 20px; margin: 1.2em 0 1em; padding: 0; font-weight: bold; color: #773098;"><span class="prefix" style="display: none;"></span><span class="content">2. inject注入并应用</span><span class="suffix" style="display: none;"></span></h3>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">在根组件 index.vue中注入</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">import { inject } from <span class="hljs-string" style="color: #D69D85; line-height: 26px;">'vue'</span>
</pre>
import { listymbol } from <span class="hljs-string" style="color: #D69D85; line-height: 26px;">'@/context/home/index'</span>
<span class="hljs-function" style="color: #DCDCDC; line-height: 26px;"><span class="hljs-title" style="color: #DCDCDC; line-height: 26px;">setup</span></span> () {
const listContext = inject(listymbol)
console.log(<span class="hljs-string" style="color: #D69D85; line-height: 26px;">"setup -> listContext"</span>, listContext)
}
<figure data-tool="mdnice编辑器" style="margin: 0; margin-top: 10px; margin-bottom: 10px; display: flex; flex-direction: column; justify-content: center; align-items: center;"></figure>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">如果你这样应用未尝不可,然而后面咱们说过了,在大的我的项目中,每个模块都可能有本人的context,为了方便管理,咱们最好是建设一个对立治理这类‘useProvide’的核心。</p>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">咱们再编辑新增一些逻辑</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">// 引入 composition api
</pre>
import { provide, ref, Ref, inject, computed, } from <span class="hljs-string" style="color: #D69D85; line-height: 26px;">'vue'</span>
// provide命名
<span class="hljs-built_in" style="color: #4EC9B0; line-height: 26px;">export</span> const listymbol = Symbol()
// 自定义hook,借用React hook命名规范,以use结尾
<span class="hljs-built_in" style="color: #4EC9B0; line-height: 26px;">export</span> const useProvide = () => {
const list = ref([])
// 获取list
const getList = async <span class="hljs-function" style="color: #DCDCDC; line-height: 26px;"><span class="hljs-title" style="color: #DCDCDC; line-height: 26px;">function</span></span> () { ... }
// 新增list
const addList = (item) => { ... }
// 删除事件
const delList = (id) => { ... },
...
// provide 裸露数据
provide(listymbol, {
list,
getList,
addList,
delList
})
// 新增的逻辑
<span class="hljs-built_in" style="color: #4EC9B0; line-height: 26px;">export</span> const useInject = () => {
const listContext = inject(listymbol);
<span class="hljs-keyword" style="color: #569CD6; line-height: 26px;">if</span> (!listContext) {
throw new Error(useListInject must be used after useListProvide
);
}
<span class="hljs-built_in" style="color: #4EC9B0; line-height: 26px;">return</span> listContext
};
}
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">index.js</p>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">对立引入并到处</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;"><span class="hljs-built_in" style="color: #4EC9B0; line-height: 26px;">export</span> { useProvide, useInject } from <span class="hljs-string" style="color: #D69D85; line-height: 26px;">'./home/index'</span>
</pre>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">index.vue</p>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">通过useProvide提供数据</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">import {useProvide} from <span class="hljs-string" style="color: #D69D85; line-height: 26px;">'@/context/index.js'</span>
</pre>
<span class="hljs-function" style="color: #DCDCDC; line-height: 26px;"><span class="hljs-title" style="color: #DCDCDC; line-height: 26px;">setup</span></span>(){
// 在顶层组件提供数据
useProvide()
}
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">inject应用</p>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">通过inject注入数据</p>
<pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;">import {useInject} from <span class="hljs-string" style="color: #D69D85; line-height: 26px;">'@/context/index.js'</span>
</pre>
<span class="hljs-function" style="color: #DCDCDC; line-height: 26px;"><span class="hljs-title" style="color: #DCDCDC; line-height: 26px;">setup</span></span>(){
// 在顶层组件提供数据
const { list, getList ...} = useInject()
<span class="hljs-built_in" style="color: #4EC9B0; line-height: 26px;">return</span> {
list,getList
}
}
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">最终,home模块的context就实现了。能够看到,在home模块下任何组件,都能够共享数据(list),以及复用解决list的公共办法。而这样做不仅避开了Vue2.x跨组件通信的坑,而且在前期的保护当中,逻辑聚合将使咱们更容易找到该数据的所有相干逻辑,而不是依照组件划分。</p>
<h2 data-tool="mdnice编辑器" style="margin-top: 30px; min-height: 32px; line-height: 28px; border-bottom: solid 1px #000000; color: #773098; display: inline-block; border-bottom-width: 1px; border-bottom-style: solid; border-color: #773098; padding-top: 5px; padding-right: 0.5em; padding-left: 0.5em; margin-bottom: -3px; font-size: 22px; margin: 1em auto; padding: 0.5em 0; text-align: center; width: 85%; font-weight: bold; display: flex; flex-direction: column; justify-content: center;"><span class="prefix" style="display: none;"></span><span class="content">最初</span><span class="suffix"></span></h2>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">如果有不对的中央,欢送留言斧正。</p>
<p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: black; margin: 1em 4px;">如果该文章对你有帮忙,欢送点赞。
扫码_搜寻联结流传款式-红色版.png</p>
</section>React 有Provider-Constmer+Hook模式,Vue 3.0 也要!
前言
相熟React的小伙伴都晓得,随着React hook的推出,React呈现了一种新型的状态治理形式 Provider-Consumer模式,能够说是真香正告。
随着Vue3.0的公布,提供了咱们属于Vue的 Hook+provider-inject的新型状态管理工具。 本篇文章将以概念+案例联合的模式为大家解说该模式的用法和长处。
文章目录:
- 引出问题,这种模式解决了什么问题?(长处)
- 如何应用,代码解构,我的项目案例。(以代码为主)
- 引出问题
首先我以自问自答的形式来引出一些问题和以往的解决方案。带着问题学习是一种很好的学习办法吧。(我要我感觉)
- 在vue中,兄弟组件、祖孙组件如何通信?
看到第一个问你,你是不是嘴角微微上扬,45度角俯视天空,微撩刘海(如果你不是秃头的话????),感觉这很easy
- Vuex;不论多简单的组件通信,Vuex好像一键搞定。然而,Vuex作为一个状态治理的重型利器,在面对大量的须要多组件共享的数据,显然是杀鸡用????????啊。况且在一个小型的Vue我的项目中,根本都不必Vuex,太重了不是么?
- EventBus;这种办法罕用于兄弟级别的组件通信。弊病也是非常明显;
- EventBus不会随着组件的销毁而主动销毁,须要咱们手销毁;
- 挂在到全局;
- 留神:肯定要记得销毁,否则会呈现bug;
- 事件产生者只能单向播送,无奈取得接收者对事件的处理结果;
- 其余(attrs,provide-inject(vue2.x的,本地缓存,url传参)。这些办法都不太罕用,尽管能勉强解决跨组件通信,但都是有种本末倒置的感觉。(我要我感觉????);
- 在Vue2.x中,如何进行逻辑复用?
举个栗子:在后盾治理我的项目中,多个菜单(组件)同时用到一堆数据,进行花色出现,有列表展现、有饼图占比、有折线图趋势、有热力求阐明频次等等,这些组件应用的是雷同的一些数据和数据处理逻辑(增删改查);如果在每个组件只都写一套这类的解决逻辑,显然是不合乎程序员的终极目标(偷懒????); 以往的解决方案:
- Mixins
- 高阶组件 (Higher-order Components, aka HOCs)
- Renderless Components (基于 scoped slots / 作用域插槽封装逻辑的组件)
其实下面在写业务代码的时候,也就mixin罕用。高阶组件和Renderless Components更多的是封装组件的时候用到的。它们存在的毛病:
- 模版中的数据起源不清晰
- 命名空间抵触。
- 须要额定的组件实例嵌套来封装逻辑(性能问题);
那么Vue将如何解决以上这些问题呢。
概念
context
咱们要利用 provide+inject+hook 创立一个上下文对象,而且对外裸露 供应者(通常在组件树中上层的地位和消费者(inject)),只有在下层组件应用provide,在上下文以内的所有子组件,通过inject都可能接见这个上下文环境以内的数据,而且不用经由过程props。也就是提供了一个汇合治理并具备响应式的对象,并限度了这个对象可接见的局限,在局限内的子组件都能猎取到她外部的值。
provide+inject
在下层组件通过 provide 提供一些变量,在子组件中能够通过 inject 来拿到
provide用法:
provide承受两个参数,第一个参数是provide惟一名称,最好用Symbol,防止反复。第二个参数是你要裸露的数据
provide(ThemeSymbol, data)
inject 用法:
inject 接管两个参数,第一个参数是provide名称,也就是ThemeSymbol,第二个参数是provide裸露进去的数据,也就是data。
Hook
Vue3.0的composition api和setup提供了Vue具备Hook的能力。而Hook的存在能够让你在组件之外封装公共办法,达到逻辑复用。所以,咱们能够在.vue组件外自定义Hook,创立context;
文件目录解构
依据下面的观点和功能,分析一下要实现的步骤:
- 建设一个公共context,封装自定义hook
- provide供给数据
- inject注入数据
这里的文件结构:
context
├─context // context的文件夹 ├─index.js // context根组件,对立引入各个模块的context,并对立裸露 │─home // 以模块名称命名,一个模块一个context │─index.js
View
├─View ├─Home ├─index.vue // 根组件,在这层注入inject ├─xxx.vue // 其余组件 消费者地点的层级
用法
为了不便解读,我这里以Todolist我的项目为例;
源码: https://github.com/961998264/todolist-vue-3.0
我的项目介绍:
- 新增待办事件
- 编辑待办事件
- 删除待办事件
- 查看待办事件
1. 建设一个上下文context
// 引入 composition apiimport { provide, ref, Ref, inject, computed, } from 'vue'// provide命名export const listymbol = Symbol()// 自定义hook,借用React hook命名规范,以use结尾export const useProvide = () => { const list = ref([]) // 获取list const getList = async function () { ... } // 新增list const addList = (item) => { ... } // 删除事件 const delList = (id) => { ... }, ... // provide 裸露数据 provide(listymbol, { list, getList, addList, delList})}
2. inject注入并应用
在根组件 index.vue中注入
import { inject } from 'vue'import { listymbol } from '@/context/home/index' setup () { const listContext = inject(listymbol) console.log("setup -> listContext", listContext) }
如果你这样应用未尝不可,然而后面咱们说过了,在大的我的项目中,每个模块都可能有本人的context,为了方便管理,咱们最好是建设一个对立治理这类‘useProvide’的核心。
咱们再编辑新增一些逻辑
// 引入 composition apiimport { provide, ref, Ref, inject, computed, } from 'vue'// provide命名export const listymbol = Symbol()// 自定义hook,借用React hook命名规范,以use结尾export const useProvide = () => { const list = ref([]) // 获取list const getList = async function () { ... } // 新增list const addList = (item) => { ... } // 删除事件 const delList = (id) => { ... }, ... // provide 裸露数据 provide(listymbol, { list, getList, addList, delList})// 新增的逻辑export const useInject = () => { const listContext = inject(listymbol); if (!listContext) { throw new Error(`useListInject must be used after useListProvide`); } return listContext};}
index.js
对立引入并到处
export { useProvide, useInject } from './home/index'
index.vue
通过useProvide提供数据
import {useProvide} from '@/context/index.js'setup(){ // 在顶层组件提供数据 useProvide()}
inject应用
通过inject注入数据
import {useInject} from '@/context/index.js'setup(){ // 在顶层组件提供数据 const { list, getList ...} = useInject() return { list,getList }}
最终,home模块的context就实现了。能够看到,在home模块下任何组件,都能够共享数据(list),以及复用解决list的公共办法。而这样做不仅避开了Vue2.x跨组件通信的坑,而且在前期的保护当中,逻辑聚合将使咱们更容易找到该数据的所有相干逻辑,而不是依照组件划分。
最初
如果有不对的中央,欢送留言斧正。
如果该文章对你有帮忙,欢送点赞。 扫码_搜寻联结流传款式-红色版.png