前提
最近发现自己一直在写很多重复性的代码,比例公司的某个项目的搜索栏有很多的下拉选择器,而我的做法是不停的初始化store、配置api、引入select组件、配置select组件,这还只是其中一个下拉选择器,如果有多个就觉得这么写是不是很傻,所以最近一直在考虑如果优化。
当重复性的工作过多的时候,就应该考虑自己的代码写的是不是有问题。
封装:把客观事物封装成抽象的类,隐藏属性和方法的实现细节,仅对外公开接口。
初步想法是减少重复性的工作,而目前我能想到的解法方法有几个:
- 用 class 抽象成一个公共的组件(这种最简单也最实用)
- 用 HOC(高阶组件)抽象成一个公共的组件
- 用 Render Props (函数子组件 FaCC)抽象成一个公共的组件
用高阶组件实现
编写 componentSelect 组件
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 39 40 41 42 43 44 45 46 47 48 49
| import React, { Component } from "react"; import { Select } from "antd"; import axios from "axios";
const WithClassName = WrappedComponent => { return class HOC extends Component { constructor(props) { super(props); this.state = { list: [] }; } componentDidMount() { this.getData(); } render() { let { list } = this.state; let { valueName, labelName } = this.props; return ( <WrappedComponent {...this.props}> {list.map(it => ( <WrappedComponent.Option value={it[valueName]} key={it[valueName]}> {it[labelName]} </WrappedComponent.Option> ))} </WrappedComponent> ); } getData() { let { params = {}, api = "" } = this.props; axios .get(api, { ...params }) .then(it => { if (it.resultObject != null) { this.setState({ list: it.resultObject }); } }) .catch(e => { console.log(e); }); } }; };
export default WithClassName(Select);
|
使用 componentSelect 组件
1 2 3 4 5 6 7 8 9 10
| import ComponentSelect from 'componentSelect'
<ComponentSelect api="/api/getSelectData" placeholder="请选择下拉" allowClear={true} valueName={'valueCode'} labelName={'valueName'} params={{ ...params }} />
|
用 Render Props (函数子组件 FaCC)实现
编写 SelectContext 组件
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
| import React, { Component } from "react"; import axios from "axios";
class SelectContext extends Component { constructor(props) { super(props); this.state = { list: [] }; } componentDidMount() { this.getData(); } render() { const { list } = this.state; const { children } = this.props; return children(list); } getData() { const { params = {}, api = "" } = this.props; axios.http .post(api, { ...params }) .then(it => { if (it.resultObject != null) { this.setState({ list: it.resultObject }); } }) .catch(e => { console.log(e); }); } }
export default SelectContext;
|
使用 SelectContext 组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import { Select } from "antd"; import SelectContext from 'componentSelect'
<SelectContext api="/api/getSelectData" params={{...params}} > {list => ( <Select placeholder="请选择" allowClear={true}> {list.map(it => ( <Select.Option value={it.value} key={it.value}> {it.name} </Select.Option> ))} </Select> )} </SelectContext>
|
注意
在 ant.design 表单中直接使用 Render Props 会出现无法取到值的情况,需要改成如下写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <SelectContext api="/api/getSelectData" params={{ ...params }}> {list => <Form.Item> {getFieldDecorator("value", {})( <Select placeholder="请选择" allowClear={true}> {list.map(it => ( <Select.Option value={it.value} key={it.value}> {it.name} </Select.Option> ))} </Select> )} </Form.Item> } </SelectContext>;
|
目前暂时不知道为何会这样,我猜应该跟 ant.design 的写法有关系