前言
今天有幸去參加了下別人公司的分享會,我帶著想讓個人給我梳理下我對高階元件瞭解比較混亂的思路,但分享的內容跟我期望方向不在一個點上,所以結束後我還是想象,我自己來梳理下自己對高階元件淺顯的理解。希望大家給予指導
要講高階元件,先讓我介紹下高階函式,這樣類比下就很容易理解了。
高階函式:以函式作為引數的函式,結果return一個函式。
(感謝有人指出錯誤,高階函式只要滿足引數或返回值為函式就可以成為高階函式,而非一定要同時滿足才成立)
高階元件:以元件作為引數的元件,結果return一個元件。
一、高階函式
高階函式(Higher Order Function),按照維基百科上面的定義,至少滿足下列一個條件的函式
- 函式作為引數傳入
- 返回值為一個函式
簡單的例子:
function add(a,b,fn){
return fn(a)+fn(b);
}
var fn=function (a){
return a*a;
}
add(2,3,fn); //13
複製程式碼
還有一些我們平時常用高階的方法,如: Map、Reduce、Filter、Sort;
以及現在常用的redux中的connect方法也是高階函式。
注:一開始我都不知道這幾個常用的方法居然就是高階函式,拿map展示下
var pow = function square(x) {
return x * x;
};
var array = [1, 2, 3, 4, 5, 6, 7, 8];
var newArr = array.map(pow); //直接傳入一個函式方法
var newArr = array.map((item) => {return item * item}); //裡面運用一個函式
//返回的一個函式
alert(newArr); // [1, 4, 9, 16, 25, 36, 49, 64]
複製程式碼
函式柯里化
在電腦科學中,柯里化(英語:Currying),又譯為卡瑞化或加里化,是把接受多個引數的函式變換成接受一個單一引數(最初函式的第一個引數)的函式,並且返回接受餘下的引數而且返回結果的新函式的技術。
對我的的理解就是函式裡面的函式分次傳進去,我自己寫了個非常簡單的例子。
var add = function(x) {
return function(y) {
return function(z){
console.log('curr',x,y,z)
return x+y+z;
};
};
};
console.log(add(1)(5)(5));//傳三個引數
///currying 1 5 5
//11
console.log(add(1)(5));//如果傳兩個引數,則會把第三個函式返回出來
/*ƒ (z) {
console.log('currying', x, y, z);
return x + y + z;
}
*/
//如果多傳則會報錯
複製程式碼
所以,我對柯里化的運用場景還是比較少的。 不知為何, 我覺得上面那個栗子有點奇怪,所以,我又試了下面這個栗子,可以無限傳參;
var add = function(action) {
var sumFun = function(doing){
var sum = '';
if(action == 'sum'){
console.log('befor',sum)
if(doing){
sum = doing;
}else{
sum = 'nothing'
}
}
console.log('lastSum='+sum);
return sumFun ;
}
return sumFun ;
};
add('sum')(2)(3)();//2 3 nothing;
add('sum')(2)(3)(4)(5);// 2 3 4 5
複製程式碼
ES6的中的寫法其實會比較清晰
var add2 = x => y => x+y;
var add3 = add2(2)
console.log('add2',add2(2)) //返回一個方法,不呼叫後面的函式
console.log('add3',add3(5)) //7
// 分步傳參,第二次呼叫時才會去執行函式。
複製程式碼
總結(我的理解):柯里化函式就是一種分步傳參的函式,可以提前傳參而不讓他執行內容,但是引數滿足時再呼叫函式。感覺可以用來做一些未知的判斷。
二、高階元件
高階元件就是一個 React 元件包裹著另外一個 React 元件。
// It's a function...
function myHOC() {
// Which returns a function that takes a component...
return function(WrappedComponent) {
// It creates a new wrapper component...
class TheHOC extends React.Component {
render() {
// And it renders the component it was given
return <WrappedComponent {...this.props} />;
}
}
// Remember: it takes a component and returns a new component
// Gotta return it here.
return TheHOC;
}
}
複製程式碼
如圖,高階元件是個純函式。 接受一個元件引數,然後在return裡面是返回一個元件。 用來把兩個類似的元件進行'封裝'?(不知用這個詞是否合適)然後在高階元件裡面把公共部分寫好,然後傳給元件。
來個好理解的例子吧
//Welcome 元件
import React, {Component} from 'react'
class Welcome extends Component {
constructor(props) {
super(props);
this.state = {
username: ''
}
}
componentWillMount() {
let username = localStorage.getItem('username');
this.setState({
username: username
})
}
render() {
return (
<div>welcome {this.state.username}</div>
)
}
}
export default Welcome;
複製程式碼
//goodbye 元件
import React, {Component} from 'react'
class Goodbye extends Component {
constructor(props) {
super(props);
this.state = {
username: ''
}
}
componentWillMount() {
let username = localStorage.getItem('username');
this.setState({
username: username
})
}
render() {
return (
<div>goodbye {this.state.username}</div>
)
}
}
export default Goodbye;
複製程式碼
從上述可見, 這兩個元件雖然功能不一樣, 但是兩個元件有許多一樣的程式碼,這樣感覺就非常的多餘。所以,我們就可以做一個高階元件來整合。
import React, {Component} from 'react'
export default (WrappedComponent) => {
class NewComponent extends Component {
constructor() {
super();
this.state = {
username: ''
}
}
componentWillMount() {
let username = localStorage.getItem('username');
this.setState({
username: username
})
}
render() {
return <WrappedComponent username={this.state.username}/>
}
}
return NewComponent
}
複製程式碼
然後分別呼叫高階元件
//高階的Welcome元件
import React, {Component} from 'react';
import wrapWithUsername from 'wrapWithUsername';
class Welcome extends Component {
render() {
return (
<div>welcome {this.props.username}</div>
)
}
}
Welcome = wrapWithUsername(Welcome);
export default Welcome;
//高階的goodbye元件
import React, {Component} from 'react';
import wrapWithUsername from 'wrapWithUsername';
class Goodbye extends Component {
render() {
return (
<div>goodbye {this.props.username}</div>
)
}
}
Goodbye = wrapWithUsername(Goodbye);
export default Goodbye;
複製程式碼
注意
1、官方推薦在高階元件裡儘量不要設定state值,傳值的話可以用props的方法。 2、儘量不去改變原始元件,而是通過組合的方式。
提供參考的博文地址:
JS中的柯里化(currying)-張鑫旭
React高階元件(譯)
助你完全理解React高階元件