高阶组件

最后更新于:2022-04-02 05:39:22

## 前言 ### 定义 > 高阶组件就是一个函数,传给它一个组件,它返回一个新的组件。 ```jsx const NewComponent = higherOrderComponent(OldComponent) ``` ### 设计核心 它的设计思想很像设计模式中的装饰者模式,为任何需要某些数据或者逻辑代码的对象提供所需然后返回。有关装饰者设计模式的解读欢迎参考我的语雀专辑:[装饰者模式](https://www.yuque.com/robinson/design-patterns/ygc1bo) ### 解决问题 主要解决数据共享或者代码逻辑共享,提高代码可复用性、可维护性。 ## 案例一 :共享数据 非常常见的是一个系统中已经登录的用户,我们是具有一定的用户信息的,假设我们知道的用户对象信息是这样的:`user:{userName:'张三',age:13}`,我们在两个组件或者说页面中都需要使用这里的数据,只不过用途不同,可以对比看下我们的写法区别。 ```jsx 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 (

用户名:{userName}

) } } } ``` ```jsx 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 () } } } ``` 优化之后,我们只需要把这部分获取用户信息拿出来即可,然后通过属性传入需要的这个数据的组件,新建一个withUser.js ```jsx 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 () } } return NewComponent } ``` 那么我们原来的用户信息的组件就会变得轻便很多。 ```jsx import withUser from './withUser' class UserInfoWithUser extends Component{ constructor(props){ super(props); this.state = { } } render(){ let {user} = this.props ; return (

用户名:{user.userName}

) } } } UserInfoWithUser = withUser(UserInfoWithUser, 'user') export default UserInfoWithUser ``` ## 案例二 :共享某些业务逻辑 方式也是一样的,主要是可以将某些组件中可以共用的方法(业务逻辑或者工具方法)提炼到另外的函数中。具体案例略。 ## 多层高阶组件 试图理解下下面的图示,假如我们的需求是从localStorage中获取数据后,属性传入一个组件, 然后再根据ajax,再属性传入一个组件,那么就会形成一个多层的高阶组件。 ![链接](https://user-gold-cdn.xitu.io/2019/3/18/1698fcb6a7530da3?w=1152&h=653&f=png&s=167165) 它的具体写法可能会是这样的:要格外注意其包裹的顺序哦。 ~~~ import wrapWithLoadData from './wrapWithLoadData' import wrapWithAjaxData from './wrapWithAjaxData' class InputWithUserName extends Component { render () { return } } InputWithUserName = wrapWithAjaxData(InputWithUserName) InputWithUserName = wrapWithLoadData(InputWithUserName, 'username') export default InputWithUserName ~~~ ## 参考文档 - 张容铭《js的设计模式》装饰者模式 - [高阶组件](http://huziketang.mangojuice.top/books/react/lesson28) - [js设计模式语雀专辑](https://www.yuque.com/robinson/design-patterns)
';