本文是學習慕課網 React高階組件課程 的筆記~css
高階組件就是接收一個組件做爲參數,而後返回一個新的組件。高階組件實際上是一個函數,並不僅是一個組件。react
加入有某需求:git
咱們對上圖進行組件拆分,能夠分爲外部modal提示框組件和內部信息兩個組件。github
外部modal組件是不變的,可是內部的內容,咱們可能在不一樣的地方會顯示不一樣的效果。以下圖。bash
因此咱們有必要去封裝一個外部的modal提示框組件,去包裹不一樣的內部組件。app
// 建立一個空項目
create-react-app xxx
複製代碼
咱們新建幾個文件。函數
// A/index.js
import React from 'react';
import './index.css';
// 定義一個函數
// 傳入一個組件做爲參數
function A(WrappedComponent) {
// 返回一個組件
return class A extends React.Component {
constructor (props) {
super(props);
this.state = {};
}
render () {
return (
<div className="a-container"> <div className="header"> <div className="title">提示</div> <div className="close">X</div> </div> <div> <!-- 在這裏使用一下 --> <WrappedComponent /> </div> </div>
)
}
}
}
// 拋出函數
export default A
複製代碼
A組件就是咱們的外部Modal提示框組件。用來包裹咱們的內部組件。學習
咱們來實現B組件。ui
// B/index.js
import React from 'react';
import A from '../A/index.js';
import './index.css';
class B extends React.Component {
render() {
return (
<div className="wrap"> <img src="https://raw.githubusercontent.com/freya0608/High-order-component/master/src/imgs/B.png" alt="" /> </div> ); } } <!--調用A()方法去包裹咱們的B組件。--> export default A(B); 複製代碼
最終實現效果爲:this
到此一個入門的高階組件實例就ok了。
總結:使用高階組件的方式:
第一種就是咱們上面的方法,第二種是利用裝飾器來實現,具體的配置你們網上能夠查到。
如今咱們又有了需求,就是B組件的內容,可能決定A組件的標題,因此這時候就須要咱們去經過B組件去傳值給A了。
// A/index.js
import React from 'react';
import './index.css';
// 這裏咱們返回一個匿名函數,接收傳遞得值
export default (title = '我是標題') => {
// 而後返回一個函數,這個函數接收子組件
return (WrappedComponent) => {
// 返回咱們的外部組件
return class A extends React.Component {
constructor (props) {
super(props);
this.state = {};
}
render () {
return (
<div className="a-container"> <div className="header"> <!--這裏使用咱們傳入的值--> <div className="title">{title}</div> <div className="close">X</div> </div> <div> <WrappedComponent /> </div> </div>
)
}
}
}
}
複製代碼
// B/index.js
import React from 'react';
import A from '../A/index.js';
import './index.css';
class B extends React.Component {
render() {
return (
<div className="wrap"> <img src="https://raw.githubusercontent.com/freya0608/High-order-component/master/src/imgs/B.png" alt="" /> </div> ); } } <!-- 最主要是這裏 --> export default A('提示i')(B); 複製代碼
這樣咱們就實現了B給A組件傳值,來讓A組件能動態的改變某些地方了。
認識代理方式的高階組件咱們要從 prop、訪問ref、抽取狀態、包裹組件四個部分來認識。
// A/index
import React from 'react';
import './index.css';
export default (title = '我是標題') => {
return (WrappedComponent) => {
return class A extends React.Component {
constructor (props) {
super(props);
this.state = {};
}
render () {
// [1] 首先咱們能夠獲取到給最外層組件傳遞的props
const prop = this.props;
console.log(prop);
return (
<div className="a-container"> <div className="header"> <div className="title">{title}</div> <div className="close">X</div> </div> <div> <!--[2] 能夠傳遞下去,傳到B組件中--> <!--[3] 另外sex是新增的--> <WrappedComponent sex={'男'} {...this.props} /> </div> </div> ) } } } } 複製代碼
// B/index.js
import React from 'react';
import A from '../A/index.js';
import './index.css';
class B extends React.Component {
render() {
return (
<div className="wrap"> <!--[1]在B組件中就能夠拿到經過A組件傳來的props--> 個人姓名: {this.props.name} 個人性別: {this.props.sex} <img src="https://raw.githubusercontent.com/freya0608/High-order-component/master/src/imgs/B.png" alt="" /> </div> ); } } export default A('提示i')(B); 複製代碼
在APP中咱們能夠設置props,傳遞到A組件,再由A組件篩選或者增長props,以後傳給B,這樣在B就能接收到最外層以及A傳遞來的props。一樣因爲A是中間層,A有權限控制B能獲得哪些props,也能額外增長一些屬性過去。
<B name={'zjj'}></B>
複製代碼
// A/index
import React from 'react';
import './index.css';
export default (title = '我是標題') => {
return (WrappedComponent) => {
return class A extends React.Component {
constructor (props) {
super(props);
this.state = {};
}
// [1] 定義一個點擊事件
handleClick = () => {
this.wref.getName();
}
render () {
const prop = this.props;
console.log(prop);
return (
<div className="a-container"> <div className="header"> <div className="title">{title}</div> <div className="close">X</div> </div> <div> <!-- 【2】綁定ref --> <WrappedComponent ref={ (v) => this.wref = v } sex={'男'} {...this.props} /> </div> <div> <!--【3】點擊事件觸發處--> <button onClick={this.handleClick}>獲取name</button> </div> </div> ) } } } } 複製代碼
咱們在B中定義一個getName方法。那麼經過點擊A中的按鈕,就能夠調用到
B/index
getName = () => {
console.log('獲取到了name')
}
複製代碼
// A.js
import React from 'react';
import './index.css';
export default (title = '我是標題') => {
return (WrappedComponent) => {
return class A extends React.Component {
constructor (props) {
super(props);
this.state = {
value: ''
};
}
// 點擊
handleClick = () => {
this.wref.getName();
}
// [1] 根據輸入設置 val
handleOnInputChange = (e) => {
this.setState({
value: e.target.value
})
}
render () {
const prop = this.props;
console.log(prop);
// [2] 設置新的props
var newProps = {
value: this.state.value, // 傳入值
onInput: this.handleOnInputChange // 監聽表單的輸入
}
return (
<div className="a-container"> <div className="header"> <div className="title">{title}</div> <div className="close">X</div> </div> <div> <WrappedComponent ref={ (v) => this.wref = v } sex={'男'} {...this.props} {...newProps} /> // 【3】傳入子組件 </div> <div> <button onClick={this.handleClick}>獲取name</button> </div> </div> ) } } } } 複製代碼
// B/index.js
// 使用傳入的值,這樣即可以將子組件內部的實現抽取出來,放到公共的組件中去,統一管理
<input type="text" value={this.props.value} onInput={this.props.onInput} />
複製代碼
其實咱們上面就是實現了包裹內部組件的效果。