<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的文件夹
  ├─index.js   // context根组件,对立引入各个模块的context,并对立裸露
  │─home      // 以模块名称命名,一个模块一个context
    │─index.js   
 
</pre>
<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
   ├─Home
     ├─index.vue  // 根组件,在这层注入inject
     ├─xxx.vue // 其余组件  消费者地点的层级
</pre>
<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
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
})
}

</pre>
<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>
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)
 }
</pre>
<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
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&nbsp;must&nbsp;be&nbsp;used&nbsp;after&nbsp;useListProvide);
  }
  <span class="hljs-built_in" style="color: #4EC9B0; line-height: 26px;">return</span> listContext
};
}

</pre>
<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>
<span class="hljs-function" style="color: #DCDCDC; line-height: 26px;"><span class="hljs-title" style="color: #DCDCDC; line-height: 26px;">setup</span></span>(){
  // 在顶层组件提供数据
  useProvide()
}
</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注入数据</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>

<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
  }
}
</pre>
<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的新型状态管理工具。 本篇文章将以概念+案例联合的模式为大家解说该模式的用法和长处。

文章目录:

  1. 引出问题,这种模式解决了什么问题?(长处)
  2. 如何应用,代码解构,我的项目案例。(以代码为主)
  3. 引出问题

首先我以自问自答的形式来引出一些问题和以往的解决方案。带着问题学习是一种很好的学习办法吧。(我要我感觉)

  1. 在vue中,兄弟组件、祖孙组件如何通信?

看到第一个问你,你是不是嘴角微微上扬,45度角俯视天空,微撩刘海(如果你不是秃头的话????),感觉这很easy

  • Vuex;不论多简单的组件通信,Vuex好像一键搞定。然而,Vuex作为一个状态治理的重型利器,在面对大量的须要多组件共享的数据,显然是杀鸡用????????啊。况且在一个小型的Vue我的项目中,根本都不必Vuex,太重了不是么?
  • EventBus;这种办法罕用于兄弟级别的组件通信。弊病也是非常明显;
  1. EventBus不会随着组件的销毁而主动销毁,须要咱们手销毁;
  2. 挂在到全局;
  3. 留神:肯定要记得销毁,否则会呈现bug;
  4. 事件产生者只能单向播送,无奈取得接收者对事件的处理结果;
  • 其余(attrs,provide-inject(vue2.x的,本地缓存,url传参)。这些办法都不太罕用,尽管能勉强解决跨组件通信,但都是有种本末倒置的感觉。(我要我感觉????);
  1. 在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. 新增待办事件
  2. 编辑待办事件
  3. 删除待办事件
  4. 查看待办事件

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