React高阶组件初探(1)

1,629 阅读2分钟

前言

定义

高阶组件就是一个函数,传给它一个组件,它返回一个新的组件。

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

参考文档