- 原文地址: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、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。