- 原文地址:Building HOCs with Recompose
- 原文作者:Abhi Aiyer
- 譯文出自:掘金翻譯計劃
- 本文永久連結:github.com/xitu/gold-m…
- 譯者:SHERlocked93
- 校對者:Eternaldeath, SeanZhouSiyuan
在 Workpop 公司,我們不斷使用不同的元件設計模式來迭代我們的產品,以適應瞬息萬變的 React 生態系統。早些時候,我們從試用高階元件設計模式(HOC)中嚐到一點甜頭。
什麼是高階元件?
高階元件只是一個函式,只不過它返回的是用來渲染 React 元件的函式。
這裡有個例子:
import {
Component
} from 'React';
export function enhancer() {
return (BaseComponent) =>
{
return class extends Component {
constructor() {
this.state = {
visible: false
};
} componentDidMount() {
this.setState({
visible: true
});
} render() {
return <
BaseComponent {...this.props
} {...this.state
} />
;
}
}
};
}複製程式碼
正如你看到的這個例子,我們只有一個給你的元件提供功能的函式。在本例中,我們新增了一些 state
來控制可見性。
我們可以看看它的使用方式:
// 展示型元件function Sample({
visible
}) {
return visible ? <
div>
I am Visible <
/div>
: <
div>
I am not Visible <
/div>
}export default enhance()(Sample);
複製程式碼
高階元件模式的意義何在?
當構建元件時,我強烈建議將展示型元件和增強型元件(高階元件)進行分離。我喜歡使用術語增強型元件來描述高階元件,是因為這個詞從字面上可以讓我們更好的理解它的用途。
增強型元件的用途:
- 可以給其他的展示型元件進行相同的程式碼複用;
- 簡化可讀性較差的臃腫的元件;
- 可以控制傳入元件的渲染;
- 可以給任何元件增加
state
,這意味著你不再需要依賴 Redux 來託管所有state
(如果你正這樣做); - 操作你傳給展示型元件的
props
(map,reduce 等任何你喜歡的方法)。
為什麼不使用類來實現它呢?
如果你想用 ES6 的類語法來實現也可以。我個人傾向於使用函式式無狀態的元件來構建應用的 UI。
function HellWorld({
message = 'Hello World'
}) {
return <
h1>
{message
}<
/h1>
;
}複製程式碼
使用函式式元件的優點:
- 模組化程式碼 — 可以在整個專案範圍內複用你的程式碼段;
- 只依賴於 props — 預設沒有 state;
- 更便於單元測試 — 對測試工具 enzyme/jest 更友好的測試介面;
- 更便於 Mock 資料 — 可以對不同場景方便的進行資料 Mock。
我們走過的旅程
然後我們開始在生產環境中深度使用高階元件了,並在使用過程中遇到了幾個問題。比如為簡單的場景不斷地編寫簡單地高階元件就很無聊,沒有將多個高階元件進行合成的方法,也無法避免開發出冗餘的高階元件(這個最麻煩,但我清楚這有時確實會發生)。人們逐漸陷入高階元件的語法和觀念中寸步難行(正如現在很多工程師的狀態),這種模式似乎也已漸漸失去了價值。
我們真正需要的解決方案是這樣的:
- 強制模式
- 易於組合
- 易於使用
這就是我們為何引入 Recompose。
開始使用 Recompose
Recompose 是一個為函式式元件和高階元件開發的 React 工具庫。可以把它當做 React 的 Lodash。
這正是我們所需要的。我們的同事們都喜歡用 Lodash,現在跟他們說開發高階元件將和使用 Lodash 有相似的開發體驗。恩,有戲。
我們來寫個簡單地 DEMO 看看:
假如我們有這樣一個元件約束:
- 需要
state
來控制可見性; - 需要將改變可見性的函式放到我們的元件中;
- 需要在元件中新增一些 props。
步驟 1 — 編寫展示型元件
export default function Presentation({
title, message, toggleVisibility, isVisible
}) {
return ( <
div>
<
h1>
{title
}<
/h1>
{isVisible ? <
p>
I'm visible<
/p>
: <
p>
Not Visible <
/p>
} <
p>
{message
}<
/p>
<
button onClick={toggleVisibility
}>
Click me! <
/button>
<
/div>
);
}複製程式碼
現在我們需要去提取這個元件的增強型元件了。
步驟 2 — 編寫容器
我通常會把一些 Recompose 的增強型元件合成在一起,所以這個步驟是建立你的 compose:
import {
compose
} from 'recompose';
export default compose( /*********************************** * * 我們將把增強型元件放在這裡 * ***********************************/)(Presentation);
複製程式碼
什麼是 Recompose 中的 compose?它相當於 Lodash
中的 flowRight
函式。
我們可以使用 compose 來將多個高階元件轉化為一個高階元件。
步驟 3 — 正確獲取 state
好了,我們現在需要從這個元件中正確獲取 state
。
在 Recompose 中,我們可以使用 withState
增強型元件來設定元件內的 state
,並且使用 withHandlers
增強型元件來設定元件的事件處理函式。
import {
compose, withState, withHandlers
} from 'recompose';
export default compose( withState('isVisible', 'toggleVis', false), withHandlers({
toggleVisibility: ({
toggleVis, isVisible
}) =>
{
return (event) =>
{
return toggleVis(!isVisible);
};
},
}))(Presentation);
複製程式碼
這裡我們設定了一個 isVisible
的 state
,一個控制可見性的方法 toggleVis
,和一個初始值 false。
withHandlers
建立了一個高階元件,它接受一系列 props
並返回一個處理函式,在這個例子中是切換可見性 state
的函式。toggleVisibility
這個函式將作為 Presentation
元件的一個 prop
。
步驟 4 — 新增 props
最後的要做的是給我們的元件附加一些 props
。
import {
compose, withState, withHandlers, withProps
} from 'recompose';
export default compose( withState('isVisible', 'toggleVis', false), withHandlers({
toggleVisibility: ({
toggleVis, isVisible
}) =>
{
return (event) =>
{
return toggleVis(!isVisible);
};
},
}), withProps(({
isVisible
}) =>
{
return {
title: isVisible ? 'This is the visible title' : 'This is the default title', message: isVisible ? 'Hello I am Visible' : 'I am not visible yet, click the button!',
};
}))(Presentation);
複製程式碼
這個模式最酷的地方在於我們現在就可以操作元件的 props
了,在這裡,通過操作控制可見性的 state
,我們可以展示不同的 title 和 message。依我看,這個增強型元件遠比原來全寫在 render 函式中的方式簡潔。
總結
現在你看到了,我們有了一個可複用的高階元件,它可以被用在其他的展示性元件上。同時可以看到我們移除了原來高階元件寫法中的很多樣板語法。
在 Recompose 中還有很多有用的 API,瞭解更多!它真的非常像 Lodash
,現在就開啟文件開始寫程式碼吧!
如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。