DailyENJS 致力於翻譯優秀的前端英文技術文章,爲技術同窗帶來更好的技術視野。前端
當我第一次據說 Hooks 時,我很是興奮。我閱讀文檔,Hooks 彷佛很神奇- 函數部件像類部件同樣功能豐富?Hooks 使得諸如生命週期或 state 之類的問題;或者是複雜的語法以及類中某些內部邏輯的低可重用性的問題獲得瞭解決。react
Hooks 使得咱們再也不須要諸如 render-props 或 HOC(高階組件)之類的複雜模式。這不只使代碼更簡潔,並且還減小了出錯的可能性。數組
複雜邏輯的可重用性也獲得了極大的改善,由於咱們如今能夠選擇將諸如 state 和「生命週期方法」直接打包到一個函數中。這爲在 Hooks 以前沒法實現的東西創造了不少能夠想象的空間。函數變得更增強大,它們不只能夠在整個項目中重複使用,並且能夠在許多不一樣的項目中重複使用。由於他們實現的邏輯能夠徹底通用。函數
我最激動的是將各類 Hook 函數組合成更強大的函數。這些函數也能夠再次組合爲功能更強大的函數。相信我,開始使用 Hooks 以後,你會離不開它。this
若是一切都那麼美好和神奇,那有什麼問題?當社區採用Hooks時,我看不到任何問題。spa
可是實際狀況是,你想在項目中使用基於類的 Hook 邏輯,而且目前沒法將這些類組件重寫爲 Hooks。類可能太複雜了,或者若是你更改它,可能會破壞項目中的許多其餘內容。這種方法的商業價值也值得懷疑。若是你轉至 React 文檔,會看到一個有趣的聲明:翻譯
可是,就像JavaScript世界中的全部內容同樣,有一個解決方案。你能夠有效地在類內使用 Hooks 邏輯,而不會違反任何 React 規則。code
我以一個簡單的 useScreenWidth Hook 爲例。從 Hook 名稱能夠看到,其目的是獲取實際的屏幕寬度。代碼:component
import { useEffect, useState } from 'react';
export function useScreenWidth(): number {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handler = (event: any) => {
setWidth(event.target.innerWidth);
};
window.addEventListener('resize', handler);
return () => {
window.removeEventListener('resize', handler);
};
}, []);
return width;
}
複製代碼
useState 和 useEffect 是 React 內置的Hooks。useState 的工做方式是返回兩個值:一個是狀態值,另外一個是它的 setter。經過數組解構,能夠將這兩個值的名稱設置爲所需的任何名稱。<variable_name>
和 set <variable_name>
是常見的命名。做爲參數,你·傳入一個初始值-在咱們的例子中,這就是當前的屏幕寬度。cdn
useEffect 是一個 hook 函數,它使用兩個參數做爲輸入:第一個是要調用的函數,第二個是 Calling objects
的數組。這意味着咱們能夠在該數組中傳遞許多對象,而且僅當數組中的至少一個值在下一個渲染時發生更改時,纔會應用 effect(或換句話說,將調用參數函數)。例如。咱們能夠將一下幾種狀況做爲第二個參數傳遞:
根據第二個參數,useEffect 能夠模仿類的生命週期方法。例如。若是咱們將 []
做爲第二個參數,僅在第一次渲染時被調用,所以它將模仿 componentDidMount
。
如上所述,鉤子的思想與類不一樣,這就是爲何根本沒有生命週期方法的緣由,而且不該以這種方式看待鉤子。useEffect 應該更多地視爲反作用。這就是爲何能夠說將 []
做爲第二個參數將模仿 componentDidMount
並賦予相同的行爲的緣由,但重要的是要理解這二者是不一樣的。
HOC 是重用組件邏輯的高級 React 技術,其使咱們可以在現有類組件中使用 Hook 邏輯。由於 HOC 是使一個組件做爲輸入,並經過一些額外的 props 返回相同的組件。在咱們的狀況下,咱們將傳遞 Hook 函數做爲 props。
import React from 'react';
import { useScreenWidth } from '../hooks/useScreenWidth';
export const withHooksHOC = (Component: any) => {
return (props: any) => {
const screenWidth = useScreenWidth();
return <Component width={screenWidth} {...props} />;
};
};
複製代碼
最後一步是用該HOC簡單包裝咱們現有的類組件。而後,咱們僅使用width屬性做爲傳遞給組件的其餘屬性。
import React from 'react';
import { withHooksHOC } from './withHooksHOC';
interface IHooksHOCProps {
width: number;
}
class HooksHOC extends React.Component<IHooksHOCProps> {
render() {
return <p style={{ fontSize: '48px' }}>width: {this.props.width}</p>;
}
}
export default withHooksHOC(HooksHOC);
複製代碼
這不會違反任何 Hooks 規則,由於咱們正在函數中使用實際的Hook-就像咱們應該使用的那樣。將邏輯做爲 props 傳遞也沒有問題。
還有另外一種實現咱們目標的方法:
import { FunctionComponent } from 'react';
import { useScreenWidth } from '../hooks/useScreenWidth';
type ScreenWidthChildren = (screenWidth: number) => any;
interface IScreenWidthProps {
children: ScreenWidthChildren;
}
export const ScreenWidth: FunctionComponent<IScreenWidthProps> = ({
children,
}) => {
const screenWidth: number = useScreenWidth();
return children(screenWidth);
};
複製代碼
如今,咱們建立了一個 Function Component,該函數將 children 做爲參數。在其中使用了 Hook 邏輯後,咱們將返回所需的結果做爲子函數。在那以後,邏輯很簡單:將建立的 Function Component導入您現有的類中,並向下傳遞 children 做爲render prop。
Hooks 是 React 世界中很大的改變,它們確定會改變咱們對 React 開發的見解。如今看來彷佛並不那麼簡單,可是幾年後,class 使用率將逐漸降低。很高興React團隊不強迫咱們重寫全部項目,也鼓勵咱們與類一塊兒使用Hooks。他們不會在不久的未來棄用 class,所以咱們固然有時間嘗試Hooks。擁有直接在類中使用 Hooks 邏輯的方法(如本文中所示),只是嘗試使用Hooks的一個優勢。
最後照舊是一個廣告貼,最近新開了一個分享技術的公衆號,歡迎你們關注👇(目前關注人數可憐🤕)