React 世界中,組成一個頁面的最小單元為一個個元件,很顯然如何合理的建立它們是個非常關鍵的點。下面介紹一下我對三種建立元件方式的理解與總結。
從簡單開始:函式式元件
瞭解過 React 的人都知道,一個 Component 資料來源有兩個:
- 來自外部的屬性(props)
- 來自內部的狀態(State)
當函式式的建立一個元件之後,顯然它已經註定了沒法再擁有自己的 State 了,只能 “無腦” 的去獲取屬性內容並展示,因為函式式元件其實是一個只實現了 render 函式的元件。
所以把這種元件稱之為 “小傻瓜元件” 非常的形象
一個 “傻瓜函式式元件” 的例子:
// 這一句匯入必須新增, JSX 語境依賴於此
import React from 'react';
export default ({order="沒人下達命令,我就啥也不幹"}) => {
return (
<div>
我是“傻瓜元件”,我完全服從命令:{order}.
</div>
);
};
複製程式碼
這個簡單的元件只接受一個 order 的 ,並且為這個屬性設定了一個預設值。
- 當使用這個元件的地方為它設定了 order 屬性,就會列印外部設定的order屬性值;
- 如果沒有設定,就會列印這個預設值(ES6 語法允許給定義的函式引數設定一個預設值)
這裡使用了 ES6 箭頭語法,快速的建立了一個無狀態的函式式元件並 exoprt 出去供外界使用。
複雜點的:繼承 React Component 相關類實現
React 版本16以後,官方已經不推薦使用 createclass 的方式建立元件了,同時也取消了以前 Mixin 那一套侵入式複用程式碼的做法,轉而推薦大家使用高階函式的方式來實現對程式碼的複用
繼承的方式建立一個元件可以繼承兩個父類:
- React.Component
- React.PureComponent
PureComponent 和 Component 除了在 shouldComponentUpdate 方法的實現邏輯上不一樣,其他表現都一樣,PureComponent使用了props和state的淺比較。
一般情況下我們選擇繼承 React.PureComponent 可以優化我們的元件效能,不過特殊時候你也可以選擇繼承 React.Component,然後自己去實現 shouldComponentUpdate 方法的邏輯部分。
相比“傻瓜式”元件,繼承方式獲得的元件更加 “聰明” 了:
1.它可以有自己的屬性 2.它可以有自己的狀態 3.它可以有自己的生命週期邏輯
一個簡單的 “聰明的” 繼承式的元件例子:
import React from "react";
import PropTypes from "prop-types";
export default class ComponentOne extends React.PureComponent {
static defaultProps = {
propOne: "預設屬性"
};
static propTypes = {
propOne: PropTypes.string.isRequired
};
constructor(props) {
super(props);
console.log("建構函式");
this.clickToAdd = this.clickToAdd.bind(this);
this.state = {
count: 0
};
}
clickToAdd() {
this.setState({
count: this.state.count + 1
});
}
componentDidMount() {
console.log("介面裝載完成");
}
render() {
return (
<div>
<div>
我是由繼承 React.PureComponent 建立的元件。並且我有屬性:{this.props.propOne}
</div>
<div>
當前計數:{this.state.count}
</div>
<div>
<button onClick={this.clickToAdd}>點選計數增加</button>
</div>
</div>
);
}
}
複製程式碼
需要注意的一點,使用繼承的方式建立的元件,它的成員函式都不會自動繫結 this,推薦在建構函式 constructor 中進行手動 bind。
上面程式碼中的元件有自己的狀態,有自己的屬性,也自己實現了生命週期函式中的 componentDidMount,在裡面簡單列印了一句 log。
更厲害的:高階元件 HOC(Higher Order Component)
高階元件,我的理解就是一個能接受元件為引數,並能返回一個新元件的函式。高階元件有下面兩種實現方式:
1. 代理模式(組合)
先看示例程式碼:
import React from 'react';
const agent = (WrappedComponent, newProps) => {
return class WrappingComponent extends React.PureComponent{
render(){
return <WrappedComponent {...this.props} {...newProps}/>
}
}
}
export default agent;
複製程式碼
WrappingComponent 和 WrappedComponent 都分別走一遍自己的生命週期,代理模式下的高階函式是兩個元件的一個組合。
可以用此來操縱傳入的 props,達到複用程式碼的目的。
2. 繼承模式(繼承)
先看示例程式碼:
import React from 'react';
const OnlyForLoginComponent = (WrappedComponent) => {
return class WrappingComponent extends WrappedComponent{
render(){
if (this.props.logined) {
return super.render();
} else {
return (
<div>
請先登入。
</div>
);
}
}
}
}
export default OnlyForLoginComponent;
複製程式碼
可以看到這裡通過繼承的方式實現了一個新的元件並返回。採用繼承的方式實現的高階元件,是一種合二為一的方式,因此我們可以操縱 WrappedComponent 的生命週期,當然也可以操縱它的屬性。
比如上面的程式碼展示的就是,使用高階元件生成了一個登入狀態判斷的狀態元件,如果登入了就繼續渲染 super(也就是 WrappedComponent),否則就提示“請先登入”。
熟悉 React-Redux 庫的同學可以探索一下它的 connect 函式,這個函式的返回值就是一個高階元件,它接受一個元件並返回一個新元件。
到此,三種主流的建立新元件的方式已經總結完畢,這些內容也是我自己在學習實踐過程中的一些總結,寫下來分享給大家,希望共同進步。