[譯] 使用 Recompose 來構建高階元件

SHERlocked93發表於2019-01-23

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);
複製程式碼

這裡我們設定了一個 isVisiblestate,一個控制可見性的方法 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 連結。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

來源:https://juejin.im/post/5c484a43e51d452ec621b6a9#comment

相關文章