當我們在說元件抽象與複用的時候我們在說什麼?本質就是元件的拆分。。
為什麼拆
“分而治之”是一個好策略。但是不要濫用,只有必要的時候才去拆分元件, 不然可能得不償失 。
拆分原則
高內聚低耦合 。
高內聚:就是把邏輯緊密相關的內容放在一個元件中。這段js,css,html都是為了實現同一個功能我們把它放在一個js檔案裡。react天生具有高內聚的特點。
低耦合:指的是不同元件之間的依賴關係要儘量弱化,也就是每個元件要儘量獨立 。 保持整個系統的低耦合度,需要對系統中的功能有充分的認識,然後根據功能點劃分模 塊,讓不同的元件去實現不同的功能
科普元件分類
函式元件(Functional Component )和類元件(Class Component)
劃分依據是根據元件的定義方式。
// 函式元件
function Hello(props) {
return <h1>Hello, {props.name}</h1>;
}
// 類元件
class Hello extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
複製程式碼
類元件可以維護自身的狀態變數,即元件的state,類元件還有不同的生命週期方法,可以讓開發者能夠在元件的不同階段(掛載、更新、解除安裝),對元件做更多的控制。 類元件這麼強大,首選類元件? 不,函式元件更加專注和單一,承擔的職責也更加清晰,它只是一個返回React 元素的函式,只關注對應UI的展現。函式元件接收外部傳入的props,返回對應UI的DOM描述,僅此而已。 函式元件的使用可以從思想上迫使你在設計元件時多做思考,更加關注邏輯和顯示的分離,設計出更加合理的頁面上元件樹的結構。實際操作上,當一個元件不需要管理自身狀態時,可以把它設計成函式元件,當你有足夠的理由發現它需要“升級”為類元件時,再把它改造為類元件。
無狀態元件(Stateless Component )和有狀態元件(Stateful Component)
劃分依據是根據元件內部是否維護state。無狀態元件內部不使用state,只根據外部元件傳入的props返回待渲染的React 元素。有狀態元件內部使用state,維護自身狀態的變化,有狀態元件根據外部元件傳入的props和自身的state,共同決定最終返回的React 元素。函式元件一定是無狀態元件,類元件則既可以充當無狀態元件,也可以充當有狀態元件
展示型元件(Presentational Component)和容器型元件(Container Component)
劃分依據是根據元件的職責.
展示型元件的職責是:元件UI長成什麼樣。展示型元件不關心元件使用的資料是如何獲取的,以及元件資料應該如何修改,它只需要知道有了這些資料後,元件UI是什麼樣子的即可。外部元件通過props傳遞給展示型元件所需的資料和修改這些資料的回撥函式,展示型元件只是它們的使用者。展示型元件一般是無狀態元件,不需要state,因為展示型元件不需要管理資料,但當展示型元件需要管理自身的UI狀態時,例如控制元件內部彈框的顯示與隱藏,是可以使用state的,這時的state屬於UI state。既然大部分情況下展示型元件不需要state,應該優先考慮使用函式元件實現展示型元件。
容器型元件的職責是:元件資料如何工作。容器型元件需要知道如何獲取子元件所需資料,以及這些資料的處理邏輯,並把資料和邏輯通過props提供給子元件使用。容器型元件一般是有狀態元件,因為它們需要管理頁面所需資料。
class UserListContainer extends React.Component{
constructor(props){
super(props);
this.state = {
users: []
}
}
componentDidMount() {
var that = this;
fetch('/path/to/user-api').then(function(response) {
response.json().then(function(data) {
that.setState({users: data})
});
});
}
render() {
return (
<UserList users={this.state.users} />
)
}
}
function UserList(props) {
return (
<div>
<ul className="user-list">
{props.users.map(function(user) {
return (
<li key={user.id}>
<span>{user.name}</span>
</li>
);
})}
</ul>
</div>
)
}
複製程式碼
這三組概念都體現了關注點分離的思想:UI展現和資料邏輯的分離。函式元件、無狀態元件和展示型元件主要關注UI展現,類元件、有狀態元件和容器型元件主要關注資料邏輯。
它們之間的關聯關係可以歸納為:函式元件一定是無狀態元件,展示型元件一般是無狀態元件;類元件既可以是有狀態元件,又可以是無狀態元件,容器型元件一般是有狀態元件。
tips:受控元件與非受控元件,業務元件,ui元件,
實現
高階元件( Higher Order Component, HOC)
並不是 React提供的某種 API,而是使 用 React 的一種模式,用於增強現有元件的功能 簡單來說,一個高階元件就是一個函式,這個函式接受一個元件作為輸入,然後返回一個新的元件作為結果,而且,返回的新元件擁有了輸入元件所不具有的功能 。 這裡提到的元件指的並不是元件例項,而是一個元件類,也可以是一個無狀態元件 的函式
import React from ’ react ’ J
function removeUserProp(WrappedComponent) {
return class WrappingComponent extends React.Component {
render() {
const {user, ... otherProps} = this.props;
return <WrappedComponent {... otherProps) />
}
}
export default removeUserProp;
複製程式碼
分類
根據返回的新元件和傳人元件引數的關係,高階元件的實現方式可以分為兩大類:
代理方式的 高階元件 :
上面的 removeUserProp例子就是一個代理方式的高階元件,特點是返回的新元件類 直接繼承自 React.Component類。 新元件扮演的角色是傳入引數元件的一個“代理”,在 新組建的 render 函式中,把被包裹元件渲染出來,除了高階元件自己要做的工作,其餘 功能全都轉手給了被包裹的元件 。
function removeUserProp(WrappedComponent) {
return function newRender(props) {
const {user, ... otherProps) = props;
return <WrappedComponent {... otherProps} />
}
}
複製程式碼
應用在下列場景中:
操縱 prop;
訪問 ref:(訪問 ref並不是值得推薦的 React元件使用方式)
抽取狀態: 其實,我們已經使用過“抽取狀態”的高階元件了,就是 react-redux 的 connect 函 數,注意 connect 函式本身並不是高階元件, connect 函式執行的結果是另 一個函式,這 個函式才是高階元件 。
包裝元件 。
const styleHOC = (WrappedComponent, style) => {
return class HOCComponent extends React.Component {
render() {
return (
<div style={style}>
<WrappedComponent {... this.props}/>
</div>
}
}
}
複製程式碼
繼承方式的高階元件 。
class PureComponent extends Component{
shouldComponentUpdate(nextProps,nextState){
const {props,state} = this;
return shallowCompare(nextProps,props) && shallowCompare(nextState,state)
}
}
複製程式碼
const modi fyProps HOC = (WrappedComponent) => {
return class NewComponent extends WrappedComponent {
render() {
const elements= super.render() ;
const newStyle = {
color: (elements && elements.type ===’div’)?’red’:’green’
}
const newProps = { ... this.props, style: newStyle};
return React.cloneElement(elements, newProps,elements.props.children);
}
}
}
複製程式碼
代理方式更加容易實現和控制,繼承方式的唯一優勢是可以操縱特定元件的生命週期函式。 “優先考慮組合,然後才考慮繼承 。”
以函式為子元件
const loggedinUser = ’ mock user ’;
class AddUserProp extends React.Component {
render() {
const user = loggedinUser ;
return this.props.children(user);
}
}
AddUserProp.propTypes = {
children: React.PropTypes.func.isRequired
}
複製程式碼
這個類的程式碼,和被增強元件的唯一聯絡就是 this.props.children,而且 this.props. children是函式型別,在 render 函式中 直接呼叫 this.props.children 函式 ,引數就是我們 希望傳遞下去的 user。 使用這個 AddUserProp 的靈活之處在於它沒有對被增強元件有任何 props 要求,只 是傳遞一個引數過去,至於怎麼使用,完全由作為子元件的函式決定
裝飾器
其他
mixin
extands