谈到react,咱们第一个想到的应该是组件,在react的眼中可真的是万物皆组件。就连咱们获取数据用到的axios也能够用组件来表示...好比,咱们能够这样封装react
<Request instance={axios.create({})} /* custom instance of axios - optional */ method="" /* get, delete, head, post, put and patch - required */ url="" /* url endpoint to be requested - required */ data={} /* post data - optional */ params={} /* queryString data - optional */ config={} /* axios config - optional */ debounce={200} /* minimum time between requests events - optional */ debounceImmediate={true} /* make the request on the beginning or trailing end of debounce - optional */ isReady={true} /* can make the axios request - optional */ onSuccess={(response)=>{}} /* called on success of axios request - optional */ onLoading={()=>{}} /* called on start of axios request - optional */ onError=(error)=>{} /* called on error of axios request - optional */ />
在项目中咱们能够这样写ios
import { AxiosProvider, Request, Get, Delete, Head, Post, Put, Patch, withAxios } from 'react-axios' ... render() { return ( <div> <Get url="/api/user" params={{id: "12345"}}> {(error, response, isLoading, makeRequest, axios) => { if(error) { return (<div>Something bad happened: {error.message} <button onClick={() => makeRequest({ params: { reload: true } })}>Retry</button></div>) } else if(isLoading) { return (<div>Loading...</div>) } else if(response !== null) { return (<div>{response.data.message} <button onClick={() => makeRequest({ params: { refresh: true } })}>Refresh</button></div>) } return (<div>Default message before request is made.</div>) }} </Get> </div> ) }
有点过度了...至少我是以为仍是要根据我的的代码习惯来吧,若是全部组件都是这么处理请求的,包括一些简单的get请求,我以为真的没这个必要,而且咱们的一些通用API也不太好统一管理redux
那么,高阶组件究竟是什么?axios
a higher-order component is a function that takes a component and returns a new component.
右键翻译 ------> 高阶组件就是一个函数,且该函数接受一个组件做为参数,并返回一个新的组件。
嗯,看起来就是这么简单,其实用起来也是api
一、具体来讲一下,咱们先用高阶函数来举个例子,一个 showUserPermit, 一个showUserVipInfo,两个函数先从localStorage读取了userVIP,以后针对userVIP作了一些处理。antd
function showUserPermit() { let vip = localStorage.getItem('u_V'); console.log(`您能够享受的${u_V}的特权...`); } function showUserVipInfo() { let vip = localStorage.getItem('u_V'); console.log(`您当前VIP等级为${u_V},升级马上...`); } showUserPermit(); showUserVipInfo();
二、咱们发现了两个API中有两个彻底同样的代码,很冗余,这样很差,咱们改一下吧app
function showUserPermit(u_V) { console.log(`您能够享受的${u_V}的特权...`); } function showUserVipInfo(u_V) { console.log(`您当前VIP等级为${u_V},升级马上...`); }
三、这样写看上去确实简单了一些,可是这两个API要想保证功能彻底必须依赖参数u_V,全部在调用这两个函数以前咱们都必需要拿到这个参数,这样未免有点耦合性,咱们再次改造
function showUserPermit(u_V) {echarts
console.log(`您能够享受的${u_V}的特权...`); } function showUserVipInfo(u_V) { console.log(`您当前VIP等级为${u_V},升级马上...`); } function wrapU_V(wrappedFunc) { let newFunc = () => { let vip = localStorage.getItem('u_V'); wrappedFunc(vip); }; return newFunc; } module.exports = { showUserPermit: wrapU_V(showUserPermit), showUserVipInfo: wrapU_V(showUserVipInfo) }
四、wrapU_V就是一个没有任何反作用的高阶函数,那么他的意义是什么?又作了什么?它帮咱们处理了u_V,而且调用了目标函数(函数参数),这样当你再次使用导出的showUserPermit的时候根本没必要要去关心u_V高低是怎么来的,到底需求什么外部条件,你只要知道它能帮我实现我想要作的事情就能够了!同时省去了每一次调用前都先要看一下它的参数是什么?怎么来?甚至根本不用关心wrapU_V内部是如何实现的,Array.map,setTimeout均可以称为高阶函数ide
高阶组件
高阶组件就是一个没有反作用的纯函数,对就是一个函数
咱们将上面的例子用component来重构一下函数
import React, {Component} from 'react' ... class showUserPermit extends Component { constructor(props) { super(props); this.state = { VIP: '' } } componentWillMount() { let VIP = localStorage.getItem('u_V'); this.setState({ VIP }) } render() { return ( <div>showUserPermit... {this.state.VIP}</div> ) } } export default showUserPermit; /* - */ import React, {Component} from 'react' ... class showUserVipInfo extends Component { constructor(props) { super(props); this.state = { VIP: '' } } componentWillMount() { let VIP = localStorage.getItem('u_V'); this.setState({ VIP }) } render() { return ( <div>showUserVipInfo... {this.state.VIP}</div> ) } } export default showUserVipInfo;
刚才发现的问题均可以映射在这两个组件里了
按照上面的思路咱们作一个处理
import React, {Component} from 'react' module.exports = Wrap: (WrappedComponent) => { class reComponent extends Component { constructor() { super(); this.state = { VIP: '' } } componentWillMount() { let VIP = localStorage.getItem('u_V'); this.setState({ VIP }) } render() { return <WrappedComponent VIP={this.state.VIP}/> } } return reComponent }
再来简化一下 showUserVipInfo和showUserPermit组件
import React, {Component} from 'react'; import {Wrap} as templete from 'wrapWithUsername'; class showUserPermit extends Component { render() { return ( <div>showUserPermit {this.props.username}</div> ) } } showUserPermit = templete(showUserPermit); export default showUserPermit; /*--*/ import React, {Component} from 'react'; import {Wrap} as templete from 'wrapWithUsername'; class showUserVipInfo extends Component { render() { return ( <div>showUserVipInfo {this.props.username}</div> ) } } showUserPermit = templete(showUserPermit); export default showUserVipInfo;
而且高阶组件中能够分布多个目标组件,举一个咱们项目中的例子
这里面右上角的时间选择组件以及echarts组件是两种不一样身份特有的一些行为和样式,其它的彻底是同样的,包括state以及共用方法都如出一辙。上代码
render() { return ( <div className="mk-genData home-module-common"> <div className="module-header"> <div className="module-title">...</div> <**GenTimerComponent** receiveTimeChange={this.getData.bind(this)}/> </div> <div className="genData-nav"> ... </div> <div> <**EchartsComponent** chartData={this.state.chartData}/> </div> </div> )
其中GenTimerComponent,和EchartsComponent都是目标组件,咱们这样导出
豁然开朗了吧,其实就是把两个组件相同的地方或者均可能用到的地方抽离出来,说句题外话,其实原本是'高阶组件'嵌套了目标组件,可是从新生成的新组建反却是继承了目标组件,看起来是一种控制反转,和Vue中的extend+minix也比较像,经过继承目标组件,除了一些静态方法,包括生命周期,state,fun,咱们均可获得
如今理解react-redux的connect函数~
把redux的state和action建立函数,经过props注入给了Component。
你在目标组件Component里面能够直接用this.props去调用redux state和action建立函数了。
ConnectedComment = connect(mapStateToProps, mapDispatchToProps)(Component);
等价于
// connect是一个返回函数的函数(就是个高阶函数) const enhance = connect(mapStateToProps, mapDispatchToProps); // 返回的函数就是一个高阶组件,该高阶组件返回一个与Redux store // 关联起来的新组件 const ConnectedComment = enhance(Component);
antd的Form也是同样的
const WrappedNormalLoginForm = Form.create()(NormalLoginForm);
总结一下: 高阶组件是对React代码进行更高层次重构的好方法,若是你想精简你的state和生命周期方法,那么高阶组件能够帮助你提取出可重用的函数。通常来讲高阶组件能完成的用组件嵌套+继承也能够,用嵌套+继承的方式理解起来其实更容易一点,特别是去重构一个复杂的组件时,经过这种方式每每更快,拆分起来更容易。至于到底用哪一个最佳还要具体看业务场景,欢迎交流探讨
做者:易企秀——Yxaw