React高階元件初探(1)

RobinsonZhang發表於2019-03-18

前言

定義

高階元件就是一個函式,傳給它一個元件,它返回一個新的元件。

const NewComponent = higherOrderComponent(OldComponent)
複製程式碼

設計核心

它的設計思想很像設計模式中的裝飾者模式,為任何需要某些資料或者邏輯程式碼的物件提供所需然後返回。有關裝飾者設計模式的解讀歡迎參考我的語雀專輯:裝飾者模式

解決問題

主要解決資料共享或者程式碼邏輯共享,提高程式碼可複用性、可維護性。

案例一 :共享資料

非常常見的是一個系統中已經登入的使用者,我們是具有一定的使用者資訊的,假設我們知道的使用者物件資訊是這樣的:user:{userName:'張三',age:13},我們在兩個元件或者說頁面中都需要使用這裡的資料,只不過用途不同,可以對比看下我們的寫法區別。

class UserInfo extends Component{
    constructor(props){
    super(props);
    this.state = {
     userName:''
    }
    }
    
    componentDidMount(){
        let user = localStorage.getItem('user') ;
       if(user){
            let userInfo = JSON.parse(user);
            let {userName} = userInfo
             this.setState({
                    userName 
               })   
        }
        render(){
            let {userName} = this.state ;
            return (<p>使用者名稱:{userName}</p>)
        }
    }
}

複製程式碼
class UserInfoChange extends Component{
    constructor(props){
    super(props);
    this.state = {
     userName:''
    }
    }
    componentDidMount(){
        let user = localStorage.getItem('user') ;
       if(user){
            let userInfo = JSON.parse(user);
            let {userName} = userInfo
             this.setState({
                    userName 
               })   
        }
        render(){
            let {userName} = this.state ;
            return (<input name='userName' defaultValue={userName}/>)
        }
    }
}

複製程式碼

優化之後,我們只需要把這部分獲取使用者資訊拿出來即可,然後通過屬性傳入需要的這個資料的元件,新建一個withUser.js

export default (WrappedComponent,name){
    class NewComponent extends Component { 
        constructor () { 
            super() ;
            this.state = { data: null } 
        }
       componentWillMount () { 
            let data = localStorage.getItem(name) ;
            this.setState({ data }) 
        } 

        render () {
            return (<WrappedComponent data={this.state.data}>)
        }
}
     return NewComponent
}
複製程式碼

那麼我們原來的使用者資訊的元件就會變得輕便很多。

import withUser from './withUser'
class UserInfoWithUser extends Component{
    constructor(props){
        super(props);
        this.state = {
        }
    }
       render(){
            let {user} = this.props ;
            return (<p>使用者名稱:{user.userName}</p>)
        }
    }
}

UserInfoWithUser = withUser(UserInfoWithUser, 'user') 
export default UserInfoWithUser
複製程式碼

案例二 :共享某些業務邏輯

方式也是一樣的,主要是可以將某些元件中可以共用的方法(業務邏輯或者工具方法)提煉到另外的函式中。具體案例略。

多層高階元件

試圖理解下下面的圖示,假如我們的需求是從localStorage中獲取資料後,屬性傳入一個元件, 然後再根據ajax,再屬性傳入一個元件,那麼就會形成一個多層的高階元件。

連結

它的具體寫法可能會是這樣的:要格外注意其包裹的順序哦。

import wrapWithLoadData from './wrapWithLoadData'
import wrapWithAjaxData from './wrapWithAjaxData'

class InputWithUserName extends Component {
  render () {
    return <input value={this.props.data} />
  }
}

InputWithUserName = wrapWithAjaxData(InputWithUserName)
InputWithUserName = wrapWithLoadData(InputWithUserName, 'username')
export default InputWithUserName
複製程式碼

參考文件

相關文章