React高阶组件(HOC)
你可以想象,在一個大型應用程序中,這種訂閱DataSource和調用setState的模式將一次又一次地發生。我們需要一個抽象,允許我們在一個地方定義這個邏輯,并在許多組件之間共享它。這正是高階組件擅長的地方。
對于訂閱了DataSource的組件,比如CommentList和BlogPost,我們可以編寫一個創建組件函數。該函數將接受一個子組件作為它的其中一個參數(可以是多個參數),該子組件將訂閱數據作為 prop。
//withSubscription為高階組件,復用邏輯提取到里面
const CommentListWrapper = withSubscription(
CommentList,
(DataSource) => DataSource.getComments()
);
const BlogPostWrapper = withSubscription(
BlogPost,
(DataSource, props) => DataSource.getBlogPost(props.id)
);
//CommentListWrapper、BlogPostWrapper分別為擴展(共享邏輯)之后的新組件
第一個參數是被包裝組件。第二個參數通過DataSource和當前的 props 返回我們需要的數據。當渲染這兩個組件時,CommentList和BlogPost將傳遞一個data?prop,其中包含從DataSource檢索到的最新數據:
// 此函數接收一個組件
function withSubscription(WrappedComponent, selectData) {
// 并返回另一個組件
return class extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
data: selectData(DataSource, props) //DataSource全局數據源
};
}
componentDidMount() {
// 負責訂閱相關的操作
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
// 清除訂閱
DataSource.removeChangeListener(this.handleChange);
}
handleChange() {
this.setState({
data: selectData(DataSource, this.props)
});
}
render() {
// 并使用新數據渲染被包裝的組件!
// 請注意,我們可能還會傳遞其他屬性
return <WrappedComponent data={this.state.data} {…this.props} />;
}
};
}
請注意,HOC 不會修改傳入的組件,也不會使用繼承來復制其行為。相反,HOC 通過將組件_包裝_在容器組件中來_組成_新組件。HOC 是純函數,沒有副作用。
被包裝組件接收來自容器組件的所有 prop,同時也接收一個新的用于 render 的data prop。HOC 不需要關心數據的使用方式或原因,而被包裝組件也不需要關心數據是怎么來的。
因為withSubscription是一個普通函數,你可以根據需要對參數進行增添或者刪除。例如,您可能希望使data?prop 的名稱可配置,以進一步將 HOC 與包裝組件隔離開來。或者你可以接受一個配置shouldComponentUpdate的參數,或者一個配置數據源的參數。因為 HOC 可以控制組件的定義方式,這一切都變得有可能。
與組件一樣,withSubscription和包裝組件之間的契約完全基于之間傳遞的 props。這種依賴方式使得替換 HOC 變得容易,只要它們為包裝的組件提供相同的 prop 即可。例如你需要改用其他庫來獲取數據的時候,這一點就很有用。
以上就是官網高階組件的經典例子,描述的也比較清楚,如果還不太明白,接下來看一個非常簡單的實例,幫助大家理解。
現在,有兩個組件,分別是Page和OtherPage:
//Page.js
import React from ‘react’;
class Page extends React.Component {
constructor(props) {
super(props);
this.state = {
msg: ‘’,
user: ‘’,
title: ‘Page’
}
}
componentDidMount(){
let greet = sessionStorage.getItem(‘greet’)
let name = sessionStorage.getItem(‘name’)
this.setState({
msg: greet,
user: name
})
}
render(){
return (
{this.state.title}
{this.state.msg}
{this.state.user}
)
}
}
export default Page
(主要觀察兩個組件之間的邏輯與功能?)
//OtherPage.js
import React from ‘react’;
class OtherPage extends React.Component {
constructor(props) {
super(props);
this.state = {
msg: ‘’,
user: ‘’,
title: ‘OtherPage’
}
}
componentDidMount(){
let greet = sessionStorage.getItem(‘greet’)
let name = sessionStorage.getItem(‘name’)
this.setState({
msg: greet,
user: name
})
}
render(){
return (
{this.state.title}
這里是關于當前組件的介紹…
{this.state.msg}
{this.state.user}
)
}
}
export default OtherPage
展示兩個組件,頁面效果如下:
展示比較簡單,主要是結合代碼,對比頁面,發現兩個組件的邏輯有一部分的代碼是相似的,同樣地試想一下,如果相似的邏輯代碼量比較大,且使用到的組件比較多,若每個組件重新寫一遍,會造成代碼重復、冗余,因此我們借鑒官網的例子,將相同邏輯的代碼單獨定義,并允許多組件之間共享,使用高階組件實現。
現在,我們需要定義一個高階組件(一個函數,參數是組件,返回一個新組件),即包裹組件,將相同邏輯提取于此。
//高階組件Wrapper.js
import React from ‘react’;
// 此函數接收一個組件與組件的標題(當然也可以是自己定義的其他擴展能力)
export default function wrapper(WrappedComponent, pageTitle) {
// 并返回一個新組件
return class extends React.Component {
constructor(props) {
super(props);
this.state = {
msg: ‘’,
user: ‘’,
title: pageTitle
};
}
componentDidMount(){
let greet = sessionStorage.getItem(‘greet’)
let name = sessionStorage.getItem(‘name’)
this.setState({
msg: greet,
user: name
})
}
render() {
// 將屬性props(或擴展能力)傳給被包裹的組件
return <WrappedComponent {…this.state} />;
}
};
}
此時,Page、OtherPage組件相應調整,去掉重復邏輯部分:
//Page.js
import React from ‘react’;
import wrapper from ‘./Wrapper’; //導入高階組件(即一個函數)
class Page extends React.Component {
render 《大廠前端面試題解析+Web核心總結學習筆記+企業項目實戰源碼+最新高清講解視頻》無償開源 徽信搜索公眾號【編程進階路】 (){ //此時相似的邏輯已經被提取到高階組件中,通過props獲取狀態或擴展能力
return (
{this.props.title}
{this.props.msg}
{this.props.user}
)
}
}
總結
以上是生活随笔為你收集整理的React高阶组件(HOC)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一文读懂机器学习,大数据/自然语言处理/
- 下一篇: DP DD VTL 备份 NBU