- 原文地址:What Hooks Mean for Vue
- 原文做者:Sarah Drasner
- 译文出自:掘金翻译计划
- 本文永久连接:github.com/xitu/gold-m…
- 译者:Ivocin
- 校对者:LeoYang, TUARAN
不要把 Hooks 和 Vue 的生命周期钩子(Lifecycle Hooks) 弄混了,Hooks 是 React 在 V16.7.0-alpha 版本中引入的,并且几天后 Vue 发布了其概念验证版本。虽然 Hooks 是由 React 提出的,它是一个对各 JavaScript 框架生态系统都有价值的、重要的组合机制,所以咱们今天会花一点时间讨论 Hooks 意味着什么。css
Hooks 主要是对模式的复用提供了一种更明确的思路 —— 避免重写组件自己,并容许有状态逻辑的不一样部分能无缝地进行协同工做。html
就 React 而言,问题在于:在表达状态的概念时,类是最多见的组件形式。无状态函数式组件也很是受欢迎,但因为它们只能单纯地渲染,因此它们的用途仅限于展现任务。前端
类自己存在一些问题。例如,随着 React 变得愈来愈流行,类的问题也广泛成为新手的阻碍。开发者为了理解 React,也必须理解类。绑定使得代码冗长且可读性差,而且须要理解 JavaScript 中的 this
。这里还讨论了使用类所带来的一些优化障碍。vue
在逻辑复用方面,咱们一般使用 render props 和高阶组件等模式。但使用这些模式后会发现本身处于相似的“厄运金字塔”中 —— 样式实现地狱,即过分使用嵌套可能会致使组件难以维护。这致使我想对 Dan Abramov 像喝醉了同样大吼大叫,没有人想要那样。react
Hooks 容许咱们使用函数调用来定义组件的有状态逻辑,从而解决这些问题。这些函数调用变得更具备组合性、可复用性,而且容许咱们在使用函数式组件的同时可以访问和维护状态。React 发布 Hooks 时,人们很兴奋 —— 下面你能够看到 Hooks 展现的一些优点,关于它们如何减小代码和重复:android
将 @dan_abramov 的代码(来自 #ReactConf2018)可视化,你能看到 React Hooks 为咱们带来的好处。pic.twitter.com/dKyOQsG0Gdios
— Pavel Prichodko (@prchdk) 2018 年 10 月 29 日git
在维护方面,简单性是关键,Hooks 提供了一种单一的、函数式的方式来实现逻辑共享,而且可能代码量更小。github
读到这里你确定想知道 Hooks 在 Vue 中必须提供什么。这彷佛是一个不须要解决的问题。毕竟,类并非 Vue 主要使用的模式。Vue 提供无状态函数式组件(若是须要它们),但为何咱们须要在函数式组件中携带状态呢?咱们有 mixins 用于组合能够在多个组件复用的相同逻辑。问题解决了。vue-cli
我想到了一样的事情,但在与 Evan You 交谈后,他指出了我忽略的一个主要用例:mixins 不能相互消费和使用状态,但 Hooks 能够。这意味着若是咱们须要链式封装逻辑,可使用 Hooks。
Hooks 实现了 mixins 的功能,但避免了 mixins 带来的两个主要问题:
若是使用多个 mixins,咱们不清楚哪一个属性是由哪一个 mixins 提供的。使用 Hooks,函数的返回值会记录消费的值。
那么,这在 Vue 中如何运行呢?咱们以前提到过,在使用 Hooks 时,逻辑在函数调用时表达从而可复用。在 Vue 中,这意味着咱们能够将数据调用、方法调用或计算属性调用封装到另外一个自定义函数中,并使它们能够自由组合。数据、方法和计算属性如今可用于函数式组件了。
让咱们来看一个很是简单的 hook,以便咱们在继续学习 Hooks 中的组合例子以前理解构建块。
好的,Vue Hooks 和 React Hooks 之间存在交叉部分。使用 use
做为前缀是 React 的约定,因此若是你在 React 中查找 Hooks,你会发现 Hooks 的名称都会像 useState
、useEffect
等。更多信息能够查看这里。
在 Evan 的在线 demo 里,你能够看到他在何处访问 useState
和 useEffect
并用于 render 函数。
若是你不熟悉 Vue 中的 render 函数,那么看一看官网文档可能会有所帮助。
可是当咱们使用 Vue 风格的 Hooks 时,咱们会如何命名呢 —— 你猜对了 —— 好比:useData
,useComputed
等。
所以,为了让咱们看看如何在 Vue 中使用 Hooks,我建立了一个示例应用程序供咱们探索。
详见视频演示:css-tricks.com/wp-content/…
在 src/hooks 文件夹中,我建立了一个 hook,它在 useMounted
hook 上阻止了滚动,并在 useDestroyed
上从新启用滚动。这有助于我在打开查看内容的对话框时暂停页面滚动,并在查看对话框结束时再次容许滚动。这是一个好的抽象功能,由于它在整个应用程序中可能会屡次使用。
import { useDestroyed, useMounted } from "vue-hooks";
export function preventscroll() {
const preventDefault = (e) => {
e = e || window.event;
if (e.preventDefault)
e.preventDefault();
e.returnValue = false;
}
// keycodes for left, up, right, down
const keys = { 37: 1, 38: 1, 39: 1, 40: 1 };
const preventDefaultForScrollKeys = (e) => {
if (keys[e.keyCode]) {
preventDefault(e);
return false;
}
}
useMounted(() => {
if (window.addEventListener) // older FF
window.addEventListener('DOMMouseScroll', preventDefault, false);
window.onwheel = preventDefault; // modern standard
window.onmousewheel = document.onmousewheel = preventDefault; // older browsers, IE
window.touchmove = preventDefault; // mobile
window.touchstart = preventDefault; // mobile
document.onkeydown = preventDefaultForScrollKeys;
});
useDestroyed(() => {
if (window.removeEventListener)
window.removeEventListener('DOMMouseScroll', preventDefault, false);
//firefox
window.addEventListener('DOMMouseScroll', (e) => {
e.stopPropagation();
}, true);
window.onmousewheel = document.onmousewheel = null;
window.onwheel = null;
window.touchmove = null;
window.touchstart = null;
document.onkeydown = null;
});
}
复制代码
而后咱们能够在像 AppDetails.vue 同样的 Vue 组件中调用它:
<script>
import { preventscroll } from "./../hooks/preventscroll.js";
...
export default {
...
hooks() {
preventscroll();
}
}
</script>
复制代码
咱们不只能够在该组件中使用它,还能够在整个应用程序中使用相同的功能!
咱们以前提到过,Hooks 和 mixins 之间的主要区别之一是 Hooks 实际上能够互相传值。让咱们看一下这个简单但有点不天然的例子。
在咱们的应用程序中,咱们须要在一个可复用的 hook 中进行计算,还有一些须要使用该计算结果的东西。在咱们的例子中,咱们有一个 hook,它获取窗口宽度并将其传递给动画,让它知道只有当咱们在更大的屏幕上时才会触发。
详见视频演示:css-tricks.com/wp-content/…
第一个 hook:
import { useData, useMounted } from 'vue-hooks';
export function windowwidth() {
const data = useData({
width: 0
})
useMounted(() => {
data.width = window.innerWidth
})
// this is something we can consume with the other hook
return {
data
}
}
复制代码
而后,在第二个 hook 中,咱们使用它来建立一个触发动画逻辑的条件:
// the data comes from the other hook
export function logolettering(data) {
useMounted(function () {
// this is the width that we stored in data from the previous hook
if (data.data.width > 1200) {
// we can use refs if they are called in the useMounted hook
const logoname = this.$refs.logoname;
Splitting({ target: logoname, by: "chars" });
TweenMax.staggerFromTo(".char", 5,
{
opacity: 0,
transformOrigin: "50% 50% -30px",
cycle: {
color: ["red", "purple", "teal"],
rotationY(i) {
return i * 50
}
}
},
...
复制代码
而后,在组件内部,咱们将一个 hook 做为参数传递给另外一个 hook:
<script>
import { logolettering } from "./../hooks/logolettering.js";
import { windowwidth } from "./../hooks/windowwidth.js";
export default {
hooks() {
logolettering(windowwidth());
}
};
</script>
复制代码
如今咱们能够在整个应用程序中使用 Hooks 来编写逻辑!再提一下,这是一个用于演示目的不太天然的例子,但你能够看到这对于大型应用程序,将逻辑保存在较小的、可复用的函数中是有效的。
Vue Hooks 如今已经能够与 Vue 2.x 一块儿使用了,但仍然是实验性的。咱们计划将 Hooks 集成到 Vue 3 中,但在咱们本身的实现中可能会偏离 React 的 API。咱们发现 React Hooks 很是鼓舞人心,正在考虑如何向 Vue 开发人员介绍其优点。咱们想以一种符合 Vue 习惯用法的方式来作,因此还有不少实验要作。
你能够查看这个仓库做为起步。Hooks 可能会成为 mixins 的替代品,因此虽然这个功能还处于早期阶段,可是一个在此期间探索其概念是有好处的。
(真诚地感谢 Evan You 和 Dan Abramov 为本文审阅。)
若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。