我们在完成搜索的需求时经常会遇到需要记录搜索条件的需求,一般是利用地址拼接搜索条件的方法
核心:切换搜索条件,把条件写入路由,然后监听路由的变化,发送搜索事件
接下来记录一个React示例:
1. 打开一个页面:
使用路由监听,去触发写好的搜索请求
export default modelExtend(pageModel, {
namespace: 'systemMessage', // 这个注意一下,连接的是下面公共的那个model
subscriptions: {
setup({ dispatch, history }) {
return history.listen(async ({ pathname, query }) => { // query的值注意
if (pathname.includes("/abc/abc")) {// 进入这路由就会触发query方法
const payload = query || { page: 1, pageSize: 10 }// 分页配置,query否使用默认配置
dispatch({
type: 'query',
payload,
})
}
})
},
},
effects: {
* query({ payload = {} }, { call, put }) {
const data = yield call(http, getMessageList(payload));//异步请求
if (data) {
yield put({
type: 'querySuccess',
payload: {
list: data.list,//这里是表格的数组数据
pagination: {// 分页的数据,如果有则记录下来
current: Number(payload.page) || 1,
pageSize: Number(payload.pageSize) || 10,
total: data.total,
},
},
})
}
},
},
2. model,一般分页会出现多次,所以建议把分页的model抽离做成单独的部分
import modelExtend from 'dva-model-extend'
export const pageModel = modelExtend(model, {
state: {
list: [],
pagination: {
current: 1,
total: 0,
pageSize: 10,
},
},
reducers: {
querySuccess(state, { payload }) { // 这里完成model数据
const { list, pagination } = payload
return {
...state,
list,
pagination: {
...state.pagination,
...pagination,
},
}
},
},
})
3. 接下来要进入组件了,主要的思路是:把地址里记录的条件信息写入你的分页和搜索条件渲染进页面,完成搜索数据的记录
@connect(({ systemMessage, loading }) => ({ systemMessage, loading }))
class RouterComponent extends PureComponent {
render() {
const { systemMessage, loading, location } = this.props;
const { query, pathname } = location // query里面就是地址的数据了
const { list, pagination} = systemMessage;// list是数据渲染表格的,pagination是分页数据
const searchList = {// 这个是搜索的配置
input: {
key: 'search',
},
select: {
label: '是否已读',
key: 'isRead',
Options: [
{label: '全部', key: ''},
{label: '是', key: '1'},
{label: '否', key: '0'}
]
},
range: {
label: '发布时间',
key: 'time'
},
onSearch: onSearch, // 这个是下面要讲的主动触发搜索的事件
filter: {// 这里是搜索条件
...query,
}
};
// 这里是page页面级,把searchList 传给你的搜索组件
4.细讲一下搜索组件的完成,我这里的搜索条件主要是搜索框(直接输入),下拉框,时间选择三个
4.1 搜索框(直接输入),下拉框,时间选择
其中值得注意的就是初始值的设置,如果地址栏有初始值,这将这个初始值写入(如果地址栏没有初始值也可以自行设置)
const { form, searchList } = this.props;
const { input, select, range, notNeedInitial, filter } = searchList;
像时间区间这种需要进行格式的转换,这个自个儿弄去吧
{input && getSearchInput(input, getFieldDecorator)}
{select && getSearchSelect(select, getFieldDecorator)}
{range && getSearchRange(range, getFieldDecorator)}
在获取表单数值的地方也有点不一样:
let fields = getFieldsValue()
fields[key] = value //看到这个你应该懂了吧
上代码
const getSearchInput = (input, getFieldDecorator) => {
return (
<Form.Item>
{getFieldDecorator(input.key, { initialValue: search })(
<Search
placeholder="input search text"
onSearch={this.handleSearch}
/>
)}
</Form.Item>
)
}
const getSearchSelect = (select, getFieldDecorator) => {
return (
<Form.Item label={select.label} style={{width: '140px'}}>
{getFieldDecorator(select.key, { initialValue: isRead || '' })(
<Select onSelect={this.handleSubmit.bind(this, select.key)}>
{
select.Options.map(item => {
return <Option value={item.key} key={item.key}>{item.label}</Option>
})
}
</Select>
)}
</Form.Item>
)
}
const getSearchRange = (range, getFieldDecorator) => {
return (
<Form.Item label={range.label}>
{getFieldDecorator(range.key, { initialValue: initialCreateTime })(
<RangePicker onChange={this.handleSubmit.bind(this, range.key)} placeholder={['开始时间', '结束时间']}/>
)}
</Form.Item>
)
}
5. 地址的跳转,然后再次进入这个路由,触发路由监听,从而发送http请求,这个方法就是主动触发的方法。
const onSearch = data => {
router.push({
pathname,
search: stringify(
{
...query,
...data,
},
{ arrayFormat: 'repeat' } // 这个是数组的可选配置项
),
})
}