目录
1. 高阶组件
定义
把组件作为参数,并返回(高阶)组件的函数,称为高阶组件
优点
- 代码复⽤,状态/逻辑抽象
- 可以对 state/event/props 进⾏劫持、操作
使用案例
假如有这样的场景,两个查询列表的⻚⾯结构相同,查询条件相同,只是表头包括操作列不⼀样:
显然这两个⻚⾯具有很⾼的复⽤性,不只是 UI 级别的复⽤,逻辑都⼏乎⼀致,这时候,⾼阶组件就派上⽤场了。我们定义查询条件的部分为组件 SearchPanel,
表格组件为 Table(antd design 的 Table ⾃带 底部分⻚区),那么这两个⻚⾯可能是下⾯的代码结构:
⻚⾯ 1,可能是普通⽤户查看⻚
import React, { Component } from 'react';
import request from 'axios';
import { Button, Table } from 'antd';
import SearchPanel from './SearchPanel';
export default class Page1 extends Component {
state = {
query: {
name: '',
id: '',
time: '',
valid: ''
},
dataSource: []
}
columns = [
{dataIndex: 'label', title: '标签'},
{dataIndex: 'action', title: '操作',
render: (_, record) => {
const onOpen = () => window.open(`/xxx/${record.id}`);
return <Button onClick={onOpen}>查看</Button>;
}
}]
onChange = (params) => {
this.setState(query => ({ ...query, ...params }));
request('/api/list', {
method: 'GET',
params
}).then(res => { // 这⾥暂不考虑异常
this.setState({ dataSource: res.data });
});
}
componentDidMount() {
this.onChange(this.state.query);
}
render() {
const { query, dataSource } = this.state;
return (
<>
<SearchPanel value={query} onChange={this.onChange} />
<Table columns={this.columns} dataSource={dataSource} />
</>
);
}
}
⻚⾯ 2,可能是管理员⻚⾯
import React, { Component } from 'react';
import request from 'axios';
import { Button, Table } from 'antd';
import SearchPanel from './SearchPanel';
export default class Page2 extends Component {
state = {
query: {
name: '',
id: '',
time: '',
valid: ''
},
dataSource: []
}
onEdit = id => {}
onDelete = id => {}
columns = [
{dataIndex: 'name', title: '名称'},
{dataIndex: 'action', title: '操作',
render: (_, record) => {
return <>
<Button onClick={() => this.onEdit(record.id)}>编辑</Button>
<Button onClick={() => this.onDelete(record.id)}>删除</Button>
</>;
}
}]
onChange = (params) => {
this.setState(query => ({ ...query, ...params }));
request('/api/list/admin', {
method: 'GET',
params
}).then(res => { // 这⾥暂不考虑异常
this.setState({ dataSource: res.data });
});
}
componentDidMount() {
this.onChange(this.state.query);
}
render() {
const { query, dataSource } = this.state;
return (
<>
<SearchPanel value={query} onChange={this.onChange} />
<Table columns={this.columns} dataSource={dataSource} />
</>
);
}
}
可以看到,两份代码除了表格列及其操作外,请求数据的接⼝也分别为 /api/list 和 /api/list/admin,这两份⽂件总计约 100 ⾏代码。我们使⽤⾼阶组件整合相同的逻辑:
Page1 和 Page2 的公共 UI 部分:
import React from 'react';
import { Table } from 'antd';
import SearchPanel from './SearchPanel';
// ⽆状态组件,所以⽤函数实现更简洁
export default function PageCommon({ query, dataSource, onChange, columns }) {
return (
<>
<SearchPanel value={query} onChange={onChange} />
<Table columns={columns} dataSource={dataSource} />
</>
);
}
⾼阶组件:
import React, { Component } from 'react';
import request from 'axios';
export default function hoc(WrappedComponent, api) {
return class extends Component {
state = {
query: {
name: '',
id: '',
time: '',
valid: ''
},
dataSource: []
}
onChange = (params) => {
this.setState(query => ({ ...query, ...params }));
request(api, {
method: 'GET',
params
}).then(res => { // 这⾥暂不考虑异常
this.setState({ dataSource: res.data });
})