Vue3 究竟好在哪里?(和 React Hook 的详细对比)

前言

这几天 Vue 3.0 Beta 版本发布了,本觉得是皆大欢喜的一件事情,可是论坛里仍是看到了不少反对的声音。主流的反对论点大概有以下几点:html

  1. 意大利面代码结构吐槽:

“太失望了。杂七杂八一堆丢在 setup 里,我还不如直接用 react”前端

个人天,3.0 这么搞的话,代码结构不清晰,语义不明确,无异于把 vue 自身优势都扔了vue

怎么感受代码结构上没有 2.0 清晰了呢 😂 这要是代码量上去了是否是很差维护啊react

  1. 抄袭 React 吐槽:

抄来抄去没本身的个性ios

有 react 香吗?愈来愈像 react 了git

在我看来,Vue 黑暗的一天还远远没有过去,不少人其实并无认真的去看 Vue-Composition-Api 文档中的 动机 章节,本文就以这个章节为线索,从 代码结构底层原理 等方面来一一打消你们的一些顾虑。程序员

在文章的开头,首先要标明一下做者的立场,我对于 React 和 Vue 都很是的喜欢。他们都有着各自的优缺点,本文绝无引战之意。两个框架都很棒!只是各有优缺点而已。React 的 Immutable 其实也带来了不少益处,而且 Hook 的思路仍是 Facebook 团队的大佬们独创的,真的是很让人赞叹的设计,我对 React 100% 致敬!github

设计动机

大如 Vue3 这种全球热门的框架,任何一个 breaking-change 的设计必定有它的深思熟虑和权衡,那么 composition-api 出现是为了解决什么问题呢?这是一个咱们须要首先思考明白的问题。面试

首先抛出 Vue2 的代码模式下存在的几个问题。vue-router

  1. 随着功能的增加,复杂组件的代码变得愈来愈难以维护。 尤为发生你去新接手别人的代码时。 根本缘由是 Vue 的现有 API 经过「选项」组织代码,可是在大部分状况下,经过逻辑考虑来组织代码更有意义。
  2. 缺乏一种比较「干净」的在多个组件之间提取和复用逻辑的机制。
  3. 类型推断不够友好。

逻辑重用

相信不少接触过 React Hook 的小伙伴已经对这种模式下组件间逻辑复用的简单性有了必定的认知,自从 React 16.7 发布以来,社区涌现出了海量的 Hook 轮子,以及主流的生态库 react-routerreact-redux 等等所有拥抱 Hook,均可以看出社区的同好们对于 Hook 开发机制的赞同。

其实组件逻辑复用在 React 中是经历了很长的一段发展历程的, mixin -> HOC & render-props -> Hookmixin 是 React 中最先启用的一种逻辑复用方式,由于它的缺点实在是多到数不清,然后面的两种也有着本身的问题,好比增长组件嵌套啊、props 来源不明确啊等等。能够说到目前为止,Hook 是相对完美的一种方案。

固然,个人一向风格就是上代码对比,我就拿 HOC 来讲吧,Github 上的一个真实的开源项目里就出现了这样的场景:

HOC 对比 Hook

class MenuBar extends React.Component {
  // props 里混合着来自各个HOC传入的属性,还有父组件传入的属性。
  handleClickNew() {
    const readyToReplaceProject = this.props.confirmReadyToReplaceProject(
      this.props.intl.formatMessage(sharedMessages.replaceProjectWarning)
    );
    this.props.onRequestCloseFile();
    if (readyToReplaceProject) {
      this.props.onClickNew(this.props.canSave && this.props.canCreateNew);
    }
    this.props.onRequestCloseFile();
  }
  handleClickRemix() {
    this.props.onClickRemix();
    this.props.onRequestCloseFile();
  }
  handleClickSave() {
    this.props.onClickSave();
    this.props.onRequestCloseFile();
  }
  handleClickSaveAsCopy() {
    this.props.onClickSaveAsCopy();
    this.props.onRequestCloseFile();
  }
}

export default compose(
  // 国际化
  injectIntl,
  // 菜单
  MenuBarHOC,
  // react-redux
  connect(mapStateToProps, mapDispatchToProps)
)(MenuBar);
复制代码

没错,这里用 compose 函数组合了好几个 HOC,其中还有 connect 这种 接受几个参数返回一个接受组件做为函数的函数 这种东西,若是你是新上手(或者哪怕是 React 老手)这套东西的人,你会在 「这个 props 是从哪一个 HOC 里来的?」,「这个 props 是外部传入的仍是 HOC 里获得的?」这些问题中迷失了大脑,最终走向堕落(误)。

不谈 HOC,个人脑子已经快炸开来了,来看看用 Hook 的方式复用逻辑是怎么样的场景吧?

function MenuBar(props) {
  // props 里只包含父组件传入的属性
  const { show } = props;
  // 菜单
  const { onClickRemix, onClickNew } = useMenuBar();
  // 国际化
  const { intl } = useIntl();
  // react-redux
  const { user } = useSelector((store) => store.user);
}

export default MenuBar;
复制代码

一切都变得很明朗,我能够很是清楚的知道这个方法的来源,intl 是哪里注入进来的,点击了 useMenuBar 后,就自动跳转到对应的逻辑,维护和可读性都极大的提升了。

固然,这是一个比较「刻意」的例子,可是相信我,我在 React 开发中已经体验过这种收益了。随着组件的「职责」愈来愈多,只要你掌握了这种代码组织的思路,那么你的组件并不会膨胀到不可读。

常见的请求场景

再举个很是常见的请求场景。

在 Vue2 中若是我须要请求一份数据,而且在loadingerror时都展现对应的视图,通常来讲,咱们会这样写:

<template>
  <div>
    <div v-if="error">failed to load</div>
    <div v-else-if="loading">loading...</div>
    <div v-else>hello {{fullName}}!</div>
  </div>
</template>

<script> import { createComponent, computed } from 'vue' export default { data() { // 集中式的data定义 若是有其余逻辑相关的数据就很容易混乱 return { data: { firstName: '', lastName: '' }, loading: false, error: false, }, }, async created() { try { // 管理loading this.loading = true // 取数据 const data = await this.$axios('/api/user') this.data = data } catch (e) { // 管理error this.error = true } finally { // 管理loading this.loading = false } }, computed() { // 没人知道这个fullName和哪一部分的异步请求有关 和哪一部分的data有关 除非仔细阅读 // 在组件大了之后更是如此 fullName() { return this.data.firstName + this.data.lastName } } } </script>
复制代码

这段代码,怎么样都谈不上优雅,凑合的把功能完成而已,而且对于loadingerror等处理的可复用性为零。

数据和逻辑也被分散在了各个option中,这还只是一个逻辑,若是又多了一些逻辑,多了datacomputedmethods?若是你是一个新接手这个文件的人,你如何迅速的分辨清楚这个method是和某两个data中的字段关联起来的?

让咱们把zeit/swr的逻辑照搬到 Vue3 中,

看一下swr在 Vue3 中的表现:

<template>
  <div>
    <div v-if="error">failed to load</div>
    <div v-else-if="loading">loading...</div>
    <div v-else>hello {{fullName}}!</div>
  </div>
</template>

<script> import { createComponent, computed } from 'vue' import useSWR from 'vue-swr' export default createComponent({ setup() { // useSWR帮你管理好了取数、缓存、甚至标签页聚焦从新请求、甚至Suspense... const { data, loading, error } = useSWR('/api/user', fetcher) // 轻松的定义计算属性 const fullName = computed(() => data.firstName + data.lastName) return { data, fullName, loading, error } } }) </script>
复制代码

就是这么简单,对吗?逻辑更加聚合了。

对了,顺嘴一提, use-swr 的威力可远远不止看到的这么简单,随便举几个它的能力:

  1. 间隔轮询

  2. 请求重复数据删除

  3. 对于同一个 key 的数据进行缓存

  4. 对数据进行乐观更新

  5. 在标签页聚焦的时候从新发起请求

  6. 分页支持

  7. 完备的 TypeScript 支持

等等等等……而这么多如此强大的能力,都在一个小小的 useSWR() 函数中,谁能说这不是魔法呢?

相似的例子还数不胜数。

umi-hooks

react-use

代码组织

上面说了那么多,还只是说了 Hook 的其中一个优点。这其实并不能解决「意大利面条代码」的问题。当逻辑多起来之后,组件的逻辑会糅合在一块儿变得一团乱麻吗?

从获取鼠标位置的需求讲起

咱们有这样一个跨组件的需求,我想在组件里得到一个响应式的变量,能实时的指向我鼠标所在的位置。

Vue 官方给出的自定义 Hook 的例子是这样的:

import { ref, onMounted, onUnmounted } from "vue";

export function useMousePosition() {
  const x = ref(0);
  const y = ref(0);

  function update(e) {
    x.value = e.pageX;
    y.value = e.pageY;
  }

  onMounted(() => {
    window.addEventListener("mousemove", update);
  });

  onUnmounted(() => {
    window.removeEventListener("mousemove", update);
  });

  return { x, y };
}
复制代码

在组件中使用:

import { useMousePosition } from "./mouse";

export default {
  setup() {
    const { x, y } = useMousePosition();
    // other logic...
    return { x, y };
  },
};
复制代码

就这么简单,无需多言。在任何组件中咱们须要「获取响应式的鼠标位置」,而且和咱们的「视图层」关联起来的时候,仅仅须要简单的一句话便可。而且这里返回的 xy 是由 ref 加工过的响应式变量,咱们能够用 watch 监听它们,能够把它们传递给其余的自定义 Hook 继续使用。几乎能作到你想要的一切,只须要发挥你的想象力。

从 Vue 官方的例子讲起

上面的例子足够入门和精简,让咱们来到现实世界。举一个 Vue CLI UI file explorer 官方吐槽的例子,这个组件是 Vue-CLI 的 gui 中(也就是日常咱们命令行里输入 vue ui 出来的那个图形化控制台)的一个复杂的文件浏览器组件,这是 Vue 官方团队的大佬写的,相信是比较有说服力的一个案例了。

这个组件有如下的几个功能:

  1. 跟踪当前文件夹状态并显示其内容

  2. 处理文件夹导航(打开,关闭,刷新...)

  3. 处理新文件夹的建立

  4. 切换显示收藏夹

  5. 切换显示隐藏文件夹

  6. 处理当前工做目录更改

文档中提出了一个尖锐的灵魂之问,你做为一个新接手的开发人员,可以在茫茫的 methoddatacomputed 等选项中一目了然的发现这个变量是属于哪一个功能吗?好比「建立新文件夹」功能使用了两个数据属性,一个计算属性和一个方法,其中该方法在距数据属性「一百行以上」的位置定义。

当一个组价中,维护同一个逻辑须要跨越上百行的「空间距离」的时候,即便是让我去维护 Vue 官方团队的代码,我也会暗搓搓的吐槽一句,「这写的什么玩意,这变量干吗用的!」

尤大很贴心的给出了一张图,在这张图中,不一样的色块表明着不一样的功能点。

其实已经作的不错了,可是在维护起来的时候仍是挺灾难的,好比淡蓝色的那个色块表明的功能。我想要完整的理清楚它的逻辑,须要「上下反复横跳」,相似的事情我已经经历过好屡次了。

而使用 Hook 之后呢?咱们能够把「新建文件夹」这个功能美美的抽到一个函数中去:

function useCreateFolder(openFolder) {
  // originally data properties
  const showNewFolder = ref(false);
  const newFolderName = ref("");

  // originally computed property
  const newFolderValid = computed(() => isValidMultiName(newFolderName.value));

  // originally a method
  async function createFolder() {
    if (!newFolderValid.value) return;
    const result = await mutate({
      mutation: FOLDER_CREATE,
      variables: {
        name: newFolderName.value,
      },
    });
    openFolder(result.data.folderCreate.path);
    newFolderName.value = "";
    showNewFolder.value = false;
  }

  return {
    showNewFolder,
    newFolderName,
    newFolderValid,
    createFolder,
  };
}
复制代码

咱们约定这些「自定义 Hook」以 use 做为前缀,和普通的函数加以区分。

右边用了 Hook 之后的代码组织色块:

咱们想要维护紫色部分功能的逻辑,那就在紫色的部分去找就行了,反正不会有其余「色块」里的变量或者方法影响到它,很快咱就改好了需求,6 点准时下班!

这是 Hook 模式下的组件概览,真的是一目了然。感受我也能够去维护 @vue/ui 了呢(假的)。

export default {
  setup() {
    // ...
  },
};

function useCurrentFolderData(networkState) {
  // ...
}

function useFolderNavigation({ networkState, currentFolderData }) {
  // ...
}

function useFavoriteFolder(currentFolderData) {
  // ...
}

function useHiddenFolders() {
  // ...
}

function useCreateFolder(openFolder) {
  // ...
}
复制代码

再来看看被吐槽成「意大利面条代码」的 setup 函数。

export default {
  setup() {
    // Network
    const { networkState } = useNetworkState();

    // Folder
    const { folders, currentFolderData } = useCurrentFolderData(networkState);
    const folderNavigation = useFolderNavigation({ networkState, currentFolderData });
    const { favoriteFolders, toggleFavorite } = useFavoriteFolders(currentFolderData);
    const { showHiddenFolders } = useHiddenFolders();
    const createFolder = useCreateFolder(folderNavigation.openFolder);

    // Current working directory
    resetCwdOnLeave();
    const { updateOnCwdChanged } = useCwdUtils();

    // Utils
    const { slicePath } = usePathUtils();

    return {
      networkState,
      folders,
      currentFolderData,
      folderNavigation,
      favoriteFolders,
      toggleFavorite,
      showHiddenFolders,
      createFolder,
      updateOnCwdChanged,
      slicePath,
    };
  },
};
复制代码

这是谁家的小仙女这么美啊!这逻辑也太清晰明了,和意大利面没半毛钱关系啊!

对比

Hook 和 Mixin & HOC 对比

说到这里,仍是不得不把官方对于「Mixin & HOC 模式」所带来的缺点整理一下。

  1. 渲染上下文中公开的属性的来源不清楚。 例如,当使用多个 mixin 读取组件的模板时,可能很难肯定从哪一个 mixin 注入了特定的属性。
  2. 命名空间冲突。 Mixins 可能会在属性和方法名称上发生冲突,而 HOC 可能会在预期的 prop 名称上发生冲突。
  3. 性能问题,HOC 和无渲染组件须要额外的有状态组件实例,这会下降性能。

而 「Hook」模式带来的好处则是:

  1. 暴露给模板的属性具备明确的来源,由于它们是从 Hook 函数返回的值。
  2. Hook 函数返回的值能够任意命名,所以不会发生名称空间冲突。
  3. 没有建立仅用于逻辑重用的没必要要的组件实例。

固然,这种模式也存在一些缺点,好比 ref 带来的心智负担,详见drawbacks

React Hook 和 Vue Hook 对比

其实 React Hook 的限制很是多,好比官方文档中就专门有一个章节介绍它的限制:

  1. 不要在循环,条件或嵌套函数中调用 Hook
  2. 确保老是在你的 React 函数的最顶层调用他们。
  3. 遵照这条规则,你就能确保 Hook 在每一次渲染中都按照一样的顺序被调用。这让 React 可以在屡次的 useState 和 useEffect 调用之间保持 hook 状态的正确。

而 Vue 带来的不一样在于:

  1. 与 React Hooks 相同级别的逻辑组合功能,但有一些重要的区别。 与 React Hook 不一样,setup 函数仅被调用一次,这在性能上比较占优。

  2. 对调用顺序没什么要求,每次渲染中不会反复调用 Hook 函数,产生的的 GC 压力较小。

  3. 没必要考虑几乎老是须要 useCallback 的问题,以防止传递函数prop给子组件的引用变化,致使无必要的从新渲染。

  4. React Hook 有臭名昭著的闭包陷阱问题(甚至成了一道热门面试题,omg),若是用户忘记传递正确的依赖项数组,useEffect 和 useMemo 可能会捕获过期的变量,这不受此问题的影响。 Vue 的自动依赖关系跟踪确保观察者和计算值始终正确无误。

  5. 不得不提一句,React Hook 里的「依赖」是须要你去手动声明的,并且官方提供了一个 eslint 插件,这个插件虽然大部分时候挺有用的,可是有时候也特别烦人,须要你手动加一行丑陋的注释去关闭它。

咱们承认 React Hooks 的创造力,这也是 Vue-Composition-Api 的主要灵感来源。上面提到的问题确实存在于 React Hook 的设计中,咱们注意到 Vue 的响应式模型刚好完美的解决了这些问题。

顺嘴一题,React Hook 的心智负担是真的很严重,若是对此感兴趣的话,请参考:

使用 react hooks 带来的收益抵得过使用它的成本吗? - 李元秋的回答 - 知乎 www.zhihu.com/question/35…

而且我本身在实际开发中,也遇到了不少问题,尤为是在我想对组件用 memo 进行一些性能优化的时候,闭包的问题爆炸式的暴露了出来。最后我用 useReducer 大法解决了其中不少问题,让我不得不怀疑这从头至尾会不会就是 Dan 的阴谋……(别想逃过 reducer

React Hook + TS 购物车实战(性能优化、闭包陷阱、自定义 hook)

原理

既然有对比,那就从原理的角度来谈一谈二者的区别,

在 Vue 中,之因此 setup 函数只执行一次,后续对于数据的更新也能够驱动视图更新,归根结底在于它的「响应式机制」,好比咱们定义了这样一个响应式的属性:

Vue

<template>
  <div>
    <span>{{count}}</span>
    <button @click="add"> +1 </button>
  </div>
</template>

export default {
    setup() {
        const count = ref(0)

        const add = () => count.value++

        return { count, add }
    }
}
复制代码

这里虽然只执行了一次 setup 可是 count 在原理上是个 「响应式对象」,对于其上 value 属性的改动,

是会触发「由 template 编译而成的 render 函数」 的从新执行的。

若是须要在 count 发生变化的时候作某件事,咱们只须要引入 effect 函数:

<template>
  <div>
    <span>{{count}}</span>
    <button @click="add"> +1 </button>
  </div>
</template>

export default {
    setup() {
        const count = ref(0)

        const add = () => count.value++

        effect(function log(){
            console.log('count changed!', count.value)
        })

        return { count, add }
    }
}
复制代码

这个 log 函数只会产生一次,这个函数在读取 count.value 的时候会收集它做为依赖,那么下次 count.value 更新后,天然而然的就能触发 log 函数从新执行了。

仔细思考一下这之间的数据关系,相信你很快就能够理解为何它能够只执行一次,可是却威力无穷。

实际上 Vue3 的 Hook 只须要一个「初始化」的过程,也就是 setup,命名很准确。它的关键字就是「只执行一次」。

React

一样的逻辑在 React 中,则是这样的写法:

export default function Counter() {
  const [count, setCount] = useState(0);

  const add = () => setCount((prev) => prev + 1);

  // 下文讲解用
  const [count2, setCount2] = useState(0);

  return (
    <div> <span>{count}</span> <button onClick={add}> +1 </button> </div>
  );
}
复制代码

它是一个函数,而父组件引入它是经过 <Counter /> 这种方式引入的,实际上它会被编译成 React.createElement(Counter) 这样的函数执行,也就是说每次渲染,这个函数都会被完整的执行一次。

useState 返回的 countsetCount 则会被保存在组件对应的 Fiber 节点上,每一个 React 函数每次执行 Hook 的顺序必须是相同的,举例来讲。 这个例子里的 useState 在初次执行的时候,因为执行了两次 useState,会在 Fiber 上保存一个 { value, setValue } -> { value2, setValue2 } 这样的链表结构。

而下一次渲染又会执行 count 的 useStatecount2 的 useState,那么 React 如何从 Fiber 节点上找出上次渲染保留下来的值呢?固然是只能按顺序找啦。

第一次执行的 useState 就拿到第一个 { value, setValue },第二个执行的就拿到第二个 { value2, setValue2 }

这也就是为何 React 严格限制 Hook 的执行顺序和禁止条件调用。

假如第一次渲染执行两次 useState,而第二次渲染时第一个 useState 被 if 条件判断给取消掉了,那么第二个 count2 的 useState 就会拿到链表中第一条的值,彻底混乱了。

若是在 React 中,要监听 count 的变化作某些事的话,会用到 useEffect 的话,那么下次 render

以后会把先后两次 render 中拿到的 useEffect 的第二个参数 deps 依赖值进行一个逐项的浅对比(对先后每一项依次调用 Object.is),好比

export default function Counter() {
  const [count, setCount] = useState(0);

  const add = () => setCount((prev) => prev + 1);

  useEffect(() => {
    console.log("count updated!", count);
  }, [count]);

  return (
    <div> <span>{count}</span> <button onClick={add}> +1 </button> </div>
  );
}
复制代码

那么,当 React 在渲染后发现 count 发生了变化,会执行 useEffect 中的回调函数。(细心的你能够观察出来,每次渲染都会从新产生一个函数引用,也就是 useEffect 的第一个参数)。

是的,React 仍是不可避免的引入了 依赖 这个概念,可是这个 依赖 是须要咱们去手动书写的,实时上 React 社区所讨论的「心智负担」也基本上是因为这个 依赖 所引发的……

因为每次渲染都会不断的执行并产生闭包,那么从性能上和 GC 压力上都会稍逊于 Vue3。它的关键字是「每次渲染都从新执行」。

关于抄袭 React Hook

其实前端开源界谈抄袭也不太好,一种新的模式的出现的值得框架之间相互借鉴和学习的,毕竟框架归根结底的目的不是为了「标榜本身的特立独行」,而是「方便广大开发者」。这是值得思考的一点,不少人彷佛以为一个框架用了某种模式,另外一个框架就不能用,其实这对于框架之间的进步和发展并无什么好处。

这里直接引用尤大在 17 年回应「Vue 借鉴虚拟 dom」的一段话吧:

再说 vdom。React 的 vdom 其实性能不怎么样。Vue 2.0 引入 vdom 的主要缘由是 vdom 把渲染过程抽象化了,从而使得组件的抽象能力也获得提高,而且能够适配 DOM 之外的渲染目标。这一点是借鉴 React 毫无争议,由于我认为 vdom 确实是个好思想。但要分清楚的是 Vue 引入 vdom 不是由于『react 有因此咱们也要有』,而是由于它确实有技术上的优越性。社区里基于 vdom 思想造的轮子海了去了,而 ng2 的渲染抽象层和 Ember Glimmer 2 的模板 -> opcode 编译也跟 vdom 有不少思想上的类似性。

这段话现在用到 Hook 上仍是同样的适用,程序员都提倡开源精神,怎么到了 Vue 和 React 之间有些人又变得小气起来了呢?说的难听点,Vue 保持本身的特立独行,那你假如换了一家新公司要你用 Vue,你不是又得从头学一遍嘛。

更况且 React 社区也同样有对 Vue 的借鉴,好比你看 react-router@6 的 api,你会发现不少地方和 vue-router 很是类似了。好比 useRoutes 的「配置式路由」,以及在组件中使子路由的代码结构等等。固然这只是我浅显的认知,不对的地方也欢迎指正。

扩展阅读

对于两种 Hook 之间的区别,想要进一步学习的同窗还能够看黄子毅大大的好文:

精读《Vue3.0 Function API》

尤小右在官方 issue 中对于 React Hook 详细的对比见解:

Why remove time slicing from vue3?

总结

其实总结下来,社区中仍是有一部分的反对观点是因为「没有好好看文档」形成的,那本文中我就花费本身一些业余时间整理社区和官方的一些观点做为一篇文章,至于看完文章之后你会不会对 Vue3 的见解有所改观,这并非我能决定的,只不过我很喜欢 Vue3,我也但愿可以尽本身的一点力量,让你们可以不要误解它。

对于意大利面代码:

  1. 提取共用的自定义 Hook(在写 React 购物车组件的时候,我提取了 3 个以上能够全局复用的 Hook)。
  2. 基于「逻辑功能」去组织代码,而不是 state 放在一块,method 放在一块,这样和用 Vue2 没什么本质上的区别(不少不少新人在用 React Hook 的时候犯这样的错误,包括我本身)。

对于心智负担:

  1. 更强大的能力意味着更多的学习成本,可是 Vue3 整体而言我以为已经把心智负担控制的很到位了。对于 ref 这个玩意,确实是须要仔细思考一下才能理解。
  2. React Hook 的心智负担已经重的出名了,在我实际的开发过程当中,有时候真的会被整到头秃…… 尤为是抽了一些自定义 Hook,deps 依赖会层层传递的状况下(随便哪一层的依赖错了,你的应用就爆炸了)。
  3. 不学习怎么能升职加薪,迎娶白富美,走向人生巅峰呢!(瞎扯)

Vue3 有多香呢?甚至《React 状态管理与同构实战》的做者、React 的忠实粉丝Lucas HC在这篇 Vue 和 React 的优势分别是什么? 中都说了这样的一句话:

我不吐槽更多了:一个 React 粉丝向 Vue3.0 致敬!

Vue3 目前也已经有了 Hook 的一些尝试:

github.com/u3u/vue-hoo…

总之,但愿看完这篇文章的你,可以更加喜欢 Vue3,对于它的到来我已是期待的不行了。

最后再次强调一下做者的立场,我对于 React 和 Vue 都很是的喜欢。他们都有着各自的优缺点,本文绝无引战之意。两个框架都很棒!只是各有优缺点而已。React 的 Immutable 其实也带来了不少益处,而且 Hook 的思路仍是 Facebook 团队的大佬们独创的,真的是很让人赞叹的设计,我对 React 100% 致敬!

本文的惟一目的就是想消除一些朋友对于 Vue 3.0 的误解,绝无他意,若有冒犯敬请谅解~

求点赞

若是本文对你有帮助,就点个赞支持下吧,你的「赞」是我持续进行创做的动力,让我知道你喜欢看个人文章吧~

❤️ 感谢你们

关注公众号「前端从进阶到入院」,有机会抽取「掘金小册 5 折优惠码」

关注公众号加好友,拉你进「前端进阶交流群」,你们一块儿共同交流和进步。

相关文章
相关标签/搜索