高階函數(shù)(HOC)
為了提高組件復(fù)用率线梗,可測試性,就要保證組件功能單?性怠益;
但是若要滿?復(fù)雜需求就要擴(kuò)展功能單?的組件仪搔,在React里就有了HOC(Higher-Order Components)的概念。
定義: ?階組件是參數(shù)為組件蜻牢,返回值為新組件的函數(shù)
最為出名的就是 redux 中的 connect函數(shù)
// hoc.js
import React from 'react'
/**
高階組件-HOC
為了了提高組件復(fù)用率烤咧,可測試性,就要保證組件功能單一性抢呆;但是
若要滿足復(fù)雜需求就要擴(kuò)展功能單一的組件煮嫌,在React里就有了
HOC(Higher-Order Components)的概念。
定義: ?高組件是參數(shù)為組件抱虐,返回值為新組件的函數(shù)
最為出名的就是 redux 中的 connect函數(shù)
*/
// foo函數(shù) 接受一個函數(shù), 返回新的組件
// Com 這里是指 function 或者 class組件
const foo = (Com) => (props) => {
return (
<div className="red-bd">
<Com {...props}></Com>
</div>
)
}
const foo2 = (Com) => (props) => {
return (
<div className="blue-bd">
<Com {...props}></Com>
</div>
)
}
// 其他寫法
// higherOrderComponent 接受了一個組件 wrappedComponent
const higherOrderComponent = (wrappedComponent)=>{
// 做些邏輯判斷可以返回其他函數(shù)
class HOC extends React.Component {
render(){
return <WrappedComponent />
}
}
// 返回一個新的組件
return HOC
}
function Child(props) {
return <div>我是Child {props.name}</div>
}
export default foo2(foo(Child))
// app.css
.red-bd {
border: 1px solid #f00;
padding: 5px;
}
.blue-bd {
border: 1px solid #00f;
padding: 5px;
}
// app.js
import React from 'react'
import Hoc from './views/Hoc'
import './App.css'
function App() {
return (
<div className="App">
<Hoc name="test" />
</div>
)
}
export default App
- 效果如下圖
image-20201010152437778
裝飾器寫法
高階組件本身是對裝飾器?模式的應(yīng)?用昌阿,自然可以利用ES7中出現(xiàn)的裝飾器語法來更優(yōu)雅的書寫代碼。
yarn add customize-cra react-app-rewired --dev
yarn add @babel/plugin-proposal-decorators --dev
更新 config-overrides.js
// config-overrides.js
//配置完成后記得重啟下
const { override, addDecoratorsLegacy } = require('customize-cra')
module.exports = override(
addDecoratorsLegacy() //配置裝飾器?
)
// 同時還要修改 package.json
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-app-rewired eject"
},
裝飾器寫法修改 Child組件
// 裝飾器寫法
// 裝飾器只能用在class組件上
// 執(zhí)行順序從下往上
@foo2
@foo
class Child1 extends Component {
render() {
return <div>我是裝飾器寫法 {this.props.name}</div>
}
}
export default Child1
使用HOC的注意事項
不要在render方法中使用HOC
React 的 diff 算法(稱為協(xié)調(diào))使?組件標(biāo)識來確定它是應(yīng)該更新現(xiàn)有子樹還是將其丟棄并掛載新子樹。 如果從 render 返回的組件與前一個渲染中的組件相同( ===)懦冰,則 React 通過將?樹與新子樹進(jìn)行區(qū)分來遞歸更新子樹灶轰。 如果它們不相等,則完全卸載前一個子樹 刷钢。
render() {
// 每次調(diào)?用 render 函數(shù)都會創(chuàng)建?一個新的
EnhancedComponent
// EnhancedComponent1 !== EnhancedComponent2
const EnhancedComponent = enhance(MyComponent);
// 這將導(dǎo)致?子樹每次渲染都會進(jìn)?行行卸載笋颤,和重新掛載的操作!
return <EnhancedComponent />;
}
不僅僅是性能問題 - 重新掛載組件會導(dǎo)致該組件及其所有子組件的狀態(tài)丟失