谈到react,我们第一个想到的应该是组件,在react的眼中可真的是万物皆组件。就连我们获取数据用到的axios也可以用组件来表示...比如,我们可以这样封装
<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 */
/>
在项目中我们可以这样写
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也不太好统一管理
那么,高阶组件到底是什么?
a higher-order component is a function that takes a component and returns a new component.
右键翻译 ------> 高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件。
嗯,看起来就是这么简单,其实用起来也是
1、具体来说一下,我们先用高阶函数来举个例子,一个 showUserPermit, 一个showUserVipInfo,两个函数先从localStorage读取了userVIP,之后针对userVIP做了一些处理。
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();
2、我们发现了两个API中有两个完全一样的代码,很冗余,这样不好,我们改一下吧
function showUserPermit(u_V) {
console.log(`您可以享受的${u_V}的特权...`);
}
function showUserVipInfo(u_V) {
console.log(`您当前VIP等级为${u_V},升级立刻...`);
}
3、这样写看上去确实简单了一些,但是这两个API要想保证功能完全必须依赖参数u_V,所有在调用这两个函数之前我们都必须要拿到这个参数,这样未免有点耦合性,我们再次改造
function showUserPermit(u_V) {
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)
}
4、wrapU_V就是一个没有任何副作用的高阶函数,那么他的意义是什么?又做了什么?它帮我们处理了u_V,并且调用了目标函数(函数参数),这样当你再次使用导出的showUserPermit的时候根本不必要去关心u_V高低是怎么来的,到底需求什么外部条件,你只要知道它能帮我实现我想要做的事情就可以了!同时省去了每一次调用前都先要看一下它的参数是什么?怎么来?甚至根本不用关心wrapU_V内部是如何实现的,Array.map,setTimeout都可以称为高阶函数
高阶组件
高阶组件就是一个没有副作用的纯函数,对就是一个函数
我们将上面的例子用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和生命周期方法,那么高阶组件可以帮助你提取出可重用的函数。一般来说高阶组件能完成的用组件嵌套+继承也可以,用嵌套+继承的方式理解起来其实更容易一点,特别是去重构一个复杂的组件时,通过这种方式往往更快,拆分起来更容易。至于到底用哪个最佳还要具体看业务场景,欢迎交流探讨
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。