javascript - 每次输入更改时如何使用服务器数据制作 antd 自动完成更新下拉列表
问题描述
我有一些使用 antd、redux、saga 的项目,特别是我使用 antd 自动完成https://ant.design/components/auto-complete/
我试图让 antd 自动完成与服务器数据一起工作,并在每次用户在输入中输入内容时发送 redux 操作。问题是我不知道如何使它与 redux saga 一起工作。
假设我成功地从服务器获取数据并使用该数据更新存储。那么如何在下拉列表中显示这些数据。每次用户类型时,下拉数据可能会更改
const {createStore, applyMiddleware} = Redux;
const {Provider, connect} = ReactRedux;
const { createAction, handleActions } = window.ReduxActions;
const createSagaMiddleware = ReduxSaga.default;
const {takeEvery, takeLatest, put, call} = ReduxSaga.effects;
const { AutoComplete } = antd;
const { Option, OptGroup } = AutoComplete;
const initialState = {
isLoading: false,
list: [],
};
var dataSource = [
{
"directionId": "3e8a6a23-d325-4c74-9bb5-e83c0bd4de4e",
"directionName": "ABC",
"items": [
{
"docflowType": 71,
"docflowTypeName": "infoABC",
"startDate": "2019-10-07T09:47:32.119004",
"endDate": "2019-10-07T09:47:32.119004",
"count": 1
}
]
},
{
"directionId": "7feb83e0-4d7b-4d99-8adb-23c25473d57d",
"directionName": "TGK",
"items": [
{
"docflowType": 74,
"docflowTypeName": "reportG",
"startDate": "2019-10-07T09:42:08.549327",
"endDate": "2019-10-07T09:42:08.549327",
"count": 1
}
]
}
]
function renderTitle(title) {
return (
<span>{title}</span>
);
}
const options = dataSource.map(group => (
<OptGroup key={group.directionId} label={renderTitle(group.directionName)}>
{group.items.map(opt => (
<Option key={opt.docflowTypeName} value={opt.docflowTypeName}>
{opt.docflowTypeName}
<span className="certain-search-item-count"> {opt.count} организаций</span>
</Option>
))}
</OptGroup>
));
const fetchSuggest = createAction('FETCH_SUGGEST_REQUEST', payload => payload);
const fetchSuggestSuccess = createAction('FETCH_SUGGEST_SUCCESS', result => result);
const fetchSuggestError = createAction('FETCH_SUGGEST_ERROR');
const autoSuggesting = handleActions(
{
[fetchSuggest]: (state, action) => ({
...state,
isLoading: true,
}),
[fetchSuggestSuccess]: (state, action) => {
console.log("fetchSuggestSuccess", action);
return {
...state,
isLoading: false,
list: action.payload,
}},
[fetchSuggestError]: (state, action) => ({
...state,
isLoading: false,
})
},
initialState
);
const fetchList = async payload => {
var {filter, exclusion} = payload || {};
const response = await axios.get(`http://someserver.com?filter=${filter}&exceptTestCodes=${exclusion}`);
return response.data;
};
function* fetchSuggestion(action) {
console.log("worker saga получает", action.payload)
try {
const data = action.payload;
const response = yield call(fetchList, data);
console.log(response);
// yield delay(200);
yield put(fetchSuggestSuccess(response));
} catch (error) {
yield put(fetchSuggestError());
}
}
function* watchInput() {
yield takeLatest('FETCH_SUGGEST_REQUEST', fetchSuggestion);
}
const sagaMiddleware = createSagaMiddleware();
const store = createStore(autoSuggesting, initialState, applyMiddleware(sagaMiddleware));
sagaMiddleware.run(watchInput);
class App extends React.Component {
constructor(props) {
super(props);
this.state = { value: '', dataSource:[] };
}
handleSearch = searchText => {
this.setState({
dataSource: !searchText ? [] : this.getListToDisplay(),
});
}
handleChange = value => {
this.setState({ value });
this.props.fetchSuggest({filter:value, exclusion: false});
}
getListToDisplay = () => {
return this.props.list.map(group => (
<OptGroup key={group.directionId} label={renderTitle(group.directionName)}>
{group.items.map(opt => (
<Option key={opt.docflowTypeName} value={opt.docflowTypeName}>
{opt.docflowTypeName}
<span className="certain-search-item-count"> {opt.count} организаций</span>
</Option>
))}
</OptGroup>
))
}
render() {
return (
<React.Fragment>
<AutoComplete
value={this.state.value}
onChange={this.handleChange}
onSearch={this.handleSearch}
onSearch={this.handleSearch}
dataSource={this.getListToDisplay()}
optionLabelProp="value"
dropdownMatchSelectWidth={false}
dropdownStyle={{ width: 405 }}
style={{ width: '30%', overflow: 'hidden' }}
// filterOption
>
</AutoComplete>
</React.Fragment>
);
}
}
const mapStateToProps = state => state;
const mapDispatchToProps = dispatch => ({ fetchSuggest: (data) => dispatch(fetchSuggest(data)) });
const ConnectedApp = connect(mapStateToProps, mapDispatchToProps)(App);
ReactDOM.render(<Provider store={store}><ConnectedApp/></Provider>, document.getElementById('root'));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.0.3/react-redux.js" crossorigin="anonymous"></script>
<script src="https://unpkg.com/redux@latest/dist/redux.js"></script>
<script src="https://unpkg.com/redux-actions@latest/dist/redux-actions.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux-saga/1.0.2/redux-saga.umd.js" crossorigin="anonymous"></script>
<script src="https://unpkg.com/babel-standalone@latest/babel.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.4.4/polyfill.min.js" crossorigin="anonymous"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://unpkg.com/moment/min/moment-with-locales.js"></script>
<script src="https://unpkg.com/antd/dist/antd-with-locales.js"></script>
<link rel="stylesheet" href="https://unpkg.com/antd/dist/antd.css" />
解决方案
这是在基于 ajax 的下拉列表的官方文档中给出的
import { Select, Spin } from 'antd';
import debounce from 'lodash/debounce';
function DebounceSelect({ fetchOptions, debounceTimeout = 800, ...props }) {
const [fetching, setFetching] = React.useState(false);
const [options, setOptions] = React.useState([]);
const fetchRef = React.useRef(0);
const debounceFetcher = React.useMemo(() => {
const loadOptions = (value) => {
fetchRef.current += 1;
const fetchId = fetchRef.current;
setOptions([]);
setFetching(true);
fetchOptions(value).then((newOptions) => {
if (fetchId !== fetchRef.current) {
// for fetch callback order
return;
}
setOptions(newOptions);
setFetching(false);
});
};
return debounce(loadOptions, debounceTimeout);
}, [fetchOptions, debounceTimeout]);
return (
<Select
labelInValue
filterOption={false}
onSearch={debounceFetcher}
notFoundContent={fetching ? <Spin size="small" /> : null}
{...props}
options={options}
/>
);
} // Usage of DebounceSelect
async function fetchUserList(username) {
console.log('fetching user', username);
return fetch('https://randomuser.me/api/?results=5')
.then((response) => response.json())
.then((body) =>
body.results.map((user) => ({
label: `${user.name.first} ${user.name.last}`,
value: user.login.username,
})),
);
}
const Demo = () => {
const [value, setValue] = React.useState([]);
return (
<DebounceSelect
mode="multiple"
value={value}
placeholder="Select users"
fetchOptions={fetchUserList}
onChange={(newValue) => {
setValue(newValue);
}}
style={{
width: '100%',
}}
/>
);
};
ReactDOM.render(<Demo />, mountNode);
推荐阅读
- distributed-system - 在客户谈判中使用 CAP 定理
- java - 如何使用带有 json 参数的 curl 调用 Web 服务?
- sql - 组合两个表并用唯一标识符替换值
- oop - 抽象类型子例程数组 - Fortran
- linux - echo 语句,即来自其他 bash shell 的标准输出,是否记录在任何地方?
- javascript - jquery - scrollTo 重新滚动元素 FIDDLE
- jupyter-notebook - Jupyterhub 升级到 0.8.1 后无法启动服务器
- javascript - 如何使用 Pure DOM 和 Vanilla JavaScript 在 JavaScript 中的列表中创建列表?
- c++ - 构造一对 unique_ptr
和整数 - typescript - Typescript: for (let key in obj), `key` 是 `Extract
` 而不仅仅是 `keyof T`,为什么?