01、介紹
React 高階組件也叫做 React HOC(High Order Component), 它是react中的高級技術, 用來重用組件邏輯。
但高階組件本身并不是React API。它只是一種模式,這種模式是由react自身的組合性質必然產生的。
那么在學習高階組件之前有一個概念我們必須清楚,就是高階函數。
02、高階函數概念:高階函數是一個函數,它接收函數作為參數或將函數作為輸出返回
舉個栗子:
接收函數作為參數
function a(x) { x(); } function b() { alert("hello"); } a(b);
將函數作為輸出返回
function a() { function b() { alert("hello"); } return b; } a()();
以上函數a就是一個高階函數, 用法非常簡單, 那么實際開發中又有哪些是高階函數呢?
Array 的 map 、reduce 、filter 等方法
Object 的 keys 、values 等方法
03、高階組件概念:高階組件就是一個函數,且該函數接受一個組件作為參數,并返回一個新的組件
舉個栗子:
// WrappedComponent 就是傳入的包裝組件 function withHoc(WrappedComponent) { return class extends Component { render () { return () } } }
withHoc 函數就是一個高階組件。那么高階組件到底有什么神奇的魔力,值得我們為之著迷?
開發組件時,我們會遇到相同的功能,使用高階組件則能減少重復代碼
04、高階組件實訓1目的: 定義高階組件
組件 Login -- 登陸頁面
// 受控組件 class Login extends Component { state = { username: "", password: "" } onUsernameChange = (e) => { this.setState({username: e.target.value}); } onPasswordChange = (e) => { this.setState({password: e.target.value}); } login = (e) => { // 禁止默認事件 e.preventDefault(); // 收集表單數據 const { username, password } = this.state; alert(`用戶名: ${username}, 密碼: ${password}`); } render () { const { username, password } = this.state; return () } }登陸
組件 Register -- 注冊頁面
// 受控組件 class Register extends Component { state = { username: "", password: "", rePassword: "" } onUsernameChange = (e) => { this.setState({username: e.target.value}); } onPasswordChange = (e) => { this.setState({password: e.target.value}); } onRePasswordChange = (e) => { this.setState({rePassword: e.target.value}); } register = (e) => { // 禁止默認事件 e.preventDefault(); // 收集表單數據 const { username, password, rePassword } = this.state; alert(`用戶名: ${username}, 密碼: ${password}, 確認密碼: ${rePassword}`); } render () { const { username, password, rePassword } = this.state; return () } }注冊
頁面效果
我們發現里面重復邏輯實在太多了,尤其是 onXxxChange 函數出現太多,我們先優化一下。
// 我們以 Register 組件為例來看 class Register extends Component { state = { username: "", password: "", rePassword: "" } // 最終修改狀態數據的函數 onChange = (stateName, stateValue) => { this.setState({[stateName]: stateValue}); } // 高階函數 --> 這樣后面就能一直復用當前函數,而不用重新創建了~ composeChange = (name) => { return (e) => this.onChange(name, e.target.value); } // 統一所有提交表單函數名 handleSubmit = (e) => { e.preventDefault(); const { username, password, rePassword } = this.state; alert(`用戶名: ${username}, 密碼: ${password}, 確認密碼: ${rePassword}`); } render () { const { username, password, rePassword } = this.state; return () } }注冊
現在兩個頁面都有 onChange 、 composeChange 、handleSubmit 函數和相關的狀態,我們接下來提取,封裝成高階組件!
// 高階組件 withHoc export default function withHoc(WrappedComponent) { return class extends Component { state = { username: "", password: "", rePassword: "" } onChange = (stateName, stateValue) => { this.setState({[stateName]: stateValue}); } composeChange = (name) => { return (e) => this.onChange(name, e.target.value); } handleSubmit = (e) => { e.preventDefault(); const { username, password, rePassword } = this.state; if (rePassword) { alert(`用戶名: ${username}, 密碼: ${password}, 確認密碼: ${rePassword}`); } else { alert(`用戶名: ${username}, 密碼: ${password}`); } } render () { // 抽取方法 const mapMethodToProps = { composeChange: this.composeChange, handleSubmit: this.handleSubmit, } // 將狀態數據和操作的方法以 props 的方式傳入的包裝組件中 return () } } // 向外暴露的是高階組件的返回值~包裝了 Register 組件返回了一個新組件 export default withHoc(Register);{/*提取公共頭部*/}) } } } // 組件 Register class Register extends Component { render () { const { handleSubmit, composeChange, username, password, rePassword } = this.props; return (xxx
現在我們提取了公共方法、狀態等數據, 封裝了一個基本的高階組件。 但是還有很多需要問題需要解決,現在開始行動~
05、高階組件實訓2目的: 向高階組件中傳參
修改高階組件
// 再次包裹了一層高階函數, 這個高階函數執行后返回值才是高階組件 // 通過這種方式, 高階組件內部就能獲取參數了~ export default (title) => (WrappedComponent) => { return class Form extends Component { ...重復代碼省略... render () { const mapMethodToProps = { composeChange: this.composeChange, handleSubmit: this.handleSubmit, } return ({/*獲取到參數值就能正常顯示了~*/}) } } }{title}
在 Login / Register 組件中使用
export default withHoc("登陸")(Login);
export default withHoc("注冊")(Register);
06、高階組件實訓3目的: 獲取父組件傳遞的 props
修改 App 組件
class App extends Component { render() { return ({/*父組件向子組件傳遞屬性*/}); } }
修改高階組件
export default (title) => (WrappedComponent) => { return class Form extends Component { ...重復代碼省略... render () { const mapMethodToProps = { composeChange: this.composeChange, handleSubmit: this.handleSubmit, } return ({/*獲取到參數值就能正常顯示了~*/}) } } }{title}
{/* 將當前組件接受到的props傳給包裝組件~*/}
Login 組件中使用
class Login extends Component { render () { const { handleSubmit, composeChange, username, password, name, age } = this.props; return (07、高階組件實訓4) } }你的名字: {name}
你的年齡: {age}
目的: 修改在 React-devtool 中高階組件名稱,方便調試
修改高階組件
export default (title) => (WrappedComponent) => { return class Form extends Component { // 定義靜態方法,修改組件在調試工具中顯示的名稱 static displayName = `Form(${getDisplayName(WrappedComponent)})` ...省略重復代碼... } } // 獲取包裝組件的displayName的方法 function getDisplayName(WrappedComponent) { return WrappedComponent.displayName || WrappedComponent.name || "Component"; }
修改之前名稱
修改之后名稱
08、使用裝飾器目的: 簡化使用高階組件
下載包
npm i react-app-rewired customize-cra @babel/plugin-proposal-decorators -D
在項目根目錄配置 config-overrides.js
const { override, addDecoratorsLegacy } = require("customize-cra"); // 修改 create-react-app 的 webpack 的配置 module.exports = override( addDecoratorsLegacy() )
修改 package.json 的 scripts
// 將 react-scripts 修改為 react-app-rewired "scripts": { "start": "react-app-rewired start", "build": "react-app-rewired build", "test": "react-app-rewired test" },
以上就是使用 decorator 的配置,修改完后就能使用了~
修改 Login 組件
@withHoc("登陸") class Login extends Component { ...省略重復代碼... } export default Login;
修改 Register 組件
@withHoc("注冊") class Register extends Component { ...省略重復代碼... } export default Register;
react-app-rewired customize-cra 是 create-react-app 2.0以上專門用來修改 webpack 的配置
decorator 還能做很多事,感興趣朋友可以看看 阮一峰ES6教程 了解更多
重復代碼永遠是我們需要考慮處理的代碼,所以我們有模塊化、組件化、工具類函數等等,
在 React 中再次引入了一個高階組件的概念,都是為了去除掉萬惡的重復代碼,讓我們代碼變得更加精簡。
本篇文章所有源碼都放在了 git倉庫,如果它對你有幫助的話,歡迎點 star ~~
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/102900.html
摘要:單頁博客應用編寫總結很久之前就想寫一個博客應用在一開始想要直接用和模板直接寫但是暑假一開始的時候不小心入了的坑所以就一不做二不休直接用寫那既然用了不寫個單頁應用也過意不去了不前前后后寫了將近兩個星期現在看來這其實是一個很容易的應用但是鑒于 React-Express單頁博客應用編寫總結 很久之前就想寫一個博客應用.在一開始想要直接用express和ejs模板直接寫, 但是暑假一開始的時...
摘要:因為工作中一直在使用,也一直以來想總結一下自己關于的一些知識經驗。于是把一些想法慢慢整理書寫下來,做成一本開源免費專業簡單的入門級別的小書,提供給社區。本書的后續可能會做成視頻版本,敬請期待。本作品采用署名禁止演繹國際許可協議進行許可 React.js 小書 本文作者:胡子大哈本文原文:React.js 小書 轉載請注明出處,保留原文鏈接以及作者信息 在線閱讀:http://huzi...
摘要:前端每周清單半年盤點之與篇前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點分為新聞熱點開發教程工程實踐深度閱讀開源項目巔峰人生等欄目。與求同存異近日,宣布將的構建工具由遷移到,引發了很多開發者的討論。 前端每周清單半年盤點之 React 與 ReactNative 篇 前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點;分為...
摘要:但如果你想更加高效地使用來開發,成為大師,那下面我要傳授的這五招你一定得認真學習一下了。雖然損失了一丟丟性能,但避免了無限的。所以我們需要設置,這些默認行為將會被去掉以上兩點的優化才能成功。陸續可能還會更新一些別的招數,敬請期待。 本文面向對象是有一定Vue.js編程經驗的開發者。如果有人需要Vue.js入門系列的文章可以在評論區告訴我,有空就給你們寫。 對大部分人來說,掌握Vue.j...
閱讀 3432·2021-11-12 10:36
閱讀 2751·2021-11-11 16:55
閱讀 2971·2021-09-27 13:36
閱讀 1623·2021-08-05 10:01
閱讀 3562·2019-08-30 15:55
閱讀 777·2019-08-30 13:01
閱讀 1915·2019-08-29 17:16
閱讀 2385·2019-08-29 16:40