import React, { PureComponent } from 'react';
import { Select, Spin } from 'antd';
import { connect } from 'dva';
import styles from './GeographicView.less';
const { Option } = Select;
const nullSlectItem = {
label: '',
key: '',
};
@connect(({ geographic }) => {
const { province, isLoading, city, area } = geographic;
return {
province,
city,
area,
isLoading,
};
})
class GeographicView extends PureComponent {
componentDidMount = () => {
const { dispatch } = this.props;
dispatch({
type: 'geographic/fetchProvince',
});
};
componentDidUpdate(props) {
const { dispatch, value } = this.props;
if (!props.value && !!value && !!value.province) {
dispatch({
type: 'geographic/fetchCity',
payload: value.province.key,
});
}
}
getProvinceOption() {
const { province } = this.props;
return this.getOption(province);
}
getCityOption = () => {
const { city } = this.props;
return this.getOption(city);
};
getAreaOption = () => {
const { city } = this.props;
return this.getOption(city);
};
getOption = list => {
if (!list || list.length < 1) {
return (
<Option key={0} value={0}>
没有找到选项
</Option>
);
}
return list.map(item => (
<Option key={item.id} value={item.id}>
{item.name}
</Option>
));
};
selectProvinceItem = item => {
const { dispatch, onChange } = this.props;
dispatch({
type: 'geographic/fetchProvince',
payload: item.key,
});
onChange({
province: item,
city: nullSlectItem,
area: nullSlectItem,
});
};
selectCityItem = item => {
const { dispatch, onChange, value } = this.props;
dispatch({
type: 'geographic/fetchCity',
payload: item.key,
});
onChange({
province: value.province,
city: item,
area: nullSlectItem,
});
};
selectAreaItem = item => {
const { value, onChange } = this.props;
onChange({
province: value.province,
city: value.city,
area: item,
});
};
conversionObject() {
const { value } = this.props;
if (!value) {
return {
province: nullSlectItem,
city: nullSlectItem,
area: nullSlectItem,
};
}
const { province, city, area } = value;
return {
province: province || nullSlectItem,
city: city || nullSlectItem,
area: area || nullSlectItem,
};
}
render() {
const { province, city, area } = this.conversionObject();
const { isLoading } = this.props;
return (
<Spin spinning={isLoading} wrapperClassName={styles.row}>
<Select
className={styles.item}
value={province}
labelInValue
showSearch
onSelect={this.selectProvinceItem}
>
{this.getProvinceOption()}
</Select>
<Select
className={styles.item}
value={city}
labelInValue
showSearch
onSelect={this.selectCityItem}
>
{this.getCityOption()}
</Select>
<Select
className={styles.item}
value={area}
labelInValue
showSearch
onSelect={this.selectAreaItem}
>
{this.getAreaOption()}
</Select>
</Spin>
);
}
}
export default GeographicView;
先上代码, 上面一段是 GeographicView.js
import { queryProvince, queryCity } from '@/services/geographic';
export default {
namespace: 'geographic',
state: {
province: [],
city: [],
area: [],
isLoading: false,
},
effects: {
*fetchProvince(_, { call, put }) {
yield put({
type: 'changeLoading',
payload: true,
});
const response = yield call(queryProvince);
yield put({
type: 'setProvince',
payload: response,
});
yield put({
type: 'changeLoading',
payload: false,
});
},
*fetchCity({ payload }, { call, put }) {
yield put({
type: 'changeLoading',
payload: true,
});
const response = yield call(queryCity, payload);
yield put({
type: 'setCity',
payload: response,
});
yield put({
type: 'changeLoading',
payload: false,
});
},
*fetchArea({ payload }, { call, put }) {
yield put({
type: 'changeLoading',
payload: true,
});
const response = yield call(queryCity, payload);
yield put({
type: 'setArea',
payload: response,
});
yield put({
type: 'changeLoading',
payload: false,
});
},
},
reducers: {
setProvince(state, action) {
return {
...state,
province: action.payload,
};
},
setCity(state, action) {
return {
...state,
city: action.payload,
};
},
setArea(state, action) {
return {
...state,
area: action.payload,
};
},
changeLoading(state, action) {
return {
...state,
isLoading: action.payload,
};
},
},
};
上面是models数据, 基于dva(redux以及saga的集成就不再详述了)
view中的部分, 关于下面一行代码的思考。
const { province, city, area } = this.conversionObject();
这里的this调用
conversionObject() { const { value } = this.props; if (!value) { return { province: nullSlectItem, city: nullSlectItem, area: nullSlectItem, }; } const { province, city, area } = value; return { province: province || nullSlectItem, city: city || nullSlectItem, area: area || nullSlectItem, }; }
该函数, 从而获取到了value的值(注意,这里的value是redux中通过models传递的 state里面的值哦(我也是刚发现还可以这么玩)
但是如果你在函数体内部输出this.props的话其实是输出为空的。 而在 render内调用则使用它的上下文也就是 class,因此能取到 props。
讲的很粗糙,还是仔细研究下代码吧,这种写法 可以很方便的封装一部分重复代码,减少重复的工作量(虽然对于新手来说增加了理解成本,但是用习惯以后,发现还真是因吹斯听呢)