问题引入

react组件提供了高端组件这么一个说法,高端组件可以部分替代组件之间的继承。是一个修饰器的模式,能够更灵活的处理一些组件复用的问题。
高阶组件本质是一个函数,此函数接受一个组件,返回一个新组件。
现在有这样一个需求,我们有很多业务,比如用户选择,订单选择,产品选择等。但是选择方式都是通过一个select选择框进行选择的,那么,可以将这个选择框提炼为一个公共组件,各个业务分装为业务组件,在一个实际的操作页面上,只要引入业务组件即可使用所有的功能。

这样的好处有:

  1. 新建一个业务组件特别简单,传入业务的url,名称和显示字段后,即可配合通用组件实现一个完整的select选择器。
  2. 提高代码的复用性,方便灵活的部署,修改基础组件的逻辑,对所有业务组件产生作用。

操作

基础组件

jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class BaseInputComp extends Component<BaseProp, BaseState> {
componentDidMount() {
const { dispatch } = this.props;
dispatch({
type: 'productBrandList/fetchList',
payload: {
pageSize: 10,
},
});
}

render() {
const {children}=this.props
function handleChange(value: any) {
console.log(`Selected: ${value}`);
}
const x = 2
const {url} = this.props
return (
<div>
<Select
size="default"
mode="multiple"
placeholder="Please select"
maxTagCount={x}
defaultValue={[]}
onChange={handleChange}
style={{width: '250px'}}
>
{children}
</Select>
{url}
</div>
);
}
}

export default BaseInputComp;

基础组件中的高阶组件,提供给人员组件用来进行封装。

jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
export function withPersistentData(name: string, url: string) {
return (WrappedComponent: any) => {
class NewComponent extends Component<BaseProp, BaseState> {
render() {
return (
<div>
<span>{name}选择</span>
<WrappedComponent url={url}{...this.props}/>
</div>
)
}
}

return NewComponent
}
}

人员组件

jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React, {Component} from "react";
import BaseInputComp, {withPersistentData} from "@/components/BaseInputComp";
import {BaseProp, BaseState} from "@/components/BaseInputComp/model";

interface UserProp extends BaseProp {
}
interface UserState extends BaseState{
}
@withPersistentData('人员','/product/info')
export default class UserComp extends Component<UserProp, UserState> {
render() {
return (
<BaseInputComp {...this.props}></BaseInputComp>
)
}
}

使用方法

jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

interface ListProps extends BaseProp {
userId: number
dispath:Dispatch
}

interface ListState extends BaseState {
}

@connect(({exampleDemoModel}: { exampleDemoModel: ExampleDemoType }) => ({userId: exampleDemoModel.userId}))
class ComponentDemo extends Component<ListProps, ListState> {
enterIconLoading = () => {
const {dispatch} = this.props;
const {userId} = this.props
dispatch({
type: "exampleDemoModel/fetchNum",
payload2: {
numCount: userId,
}
})
};
render() {
const {userId} = this.props
return (
<div>
当前userId:{userId}<br/><br/>
<Button onClick={this.enterIconLoading}>切换UserId</Button><br/><br/>
<UserComp {...this.props}/>
</div>
)
}

}

export default Form.create<ListProps & FormComponentProps>()(ComponentDemo);