刚开始学习RxJS并喜欢它,但是有一个我无法解决的问题。
它如何工作:您可以按关键字搜索。但是首先应将关键字发送到服务器进行分析,然后将分析结果存储在商店中,然后将分析结果用于搜索查询。
我已经找到了如何获取和保存关键字分析结果以及如何发送搜索请求的方法,但是找不到如何结合使用。对我来说,主要问题是如何检查商店中是否已有关键字,然后仅跳过第一部分并发送搜索请求。
const initialState = {
keywords: {}, // keywords cache
query: [], // current query
items: [], // search result
error: null,
};
const reducers = {
setQuery: (state, { payload }) => {
state.query = payload;
},
setItems: (state, { payload }) => {
state.items = payload;
},
setError: (state, { payload }) => {
state.error = payload;
},
addKeyword: (state, { payload }) => {
state.keywords[payload.keyword] = payload;
},
};
const search = createSlice({
initialState,
reducers,
});
const { actions } = search;
const setQueryEpic = (action$, state$) => action$.pipe(
ofType(actions.setQuery.type),
// This part is skipped if all keywords already in state
flatMap(({ payload }) => payload),
filter(keyword => !state$.value.keywords[keyword]),
mergeMap(
keyword => ajax
.getJSON(`/analyze/keyword?keyword=${keyword}`),
),
map(keywordData => actions.addKeyword(keywordData)),
// This part does request and set search result. Should wait for keywords analyze
switchMap((action) => {
const state = state$.value
const params = {
keywords_vectors: state.query.map(queryKeywords => state.keywords[queryKeywords].vector),
};
return ajax
.post(`/search`, JSON.stringify(params))
.pipe(
map(data => data.response.items),
);
}),
map(items => actions.setItems(items)),
catchError(error => of(actions.setError(error.message))),
);
更新:找到了此解决方案
const setQueryEpic = (action$, state$) => action$.pipe(
ofType(actions.setQuery.type),
flatMap(({ payload }) => {
const requests = payload.map((keyword) => {
if (state$.value.keywords[keyword]) {
// keyword in cache
return of(state$.value.keywords[keyword]);
}
// analyze new keyword
return ajax
.getJSON(`/analyze/keyword?keyword=${keyword}`)
});
// wait for all requests
return forkJoin(requests);
}),
switchMap((keywords) => {
const params = {
keywords_vectors: keywords.map(data => data.vector),
};
// create actions to add keywords to cache
const addKeywordActions = keywords
.filter(data => !state$.value.keywords[data.keyword])
.map(data => actions.addKeyword(data));
return ajax
.post(`/search`, JSON.stringify(params))
.pipe(
map(data => data.response.items),
// combine all actions
map(items => [actions.setItems(items), ...addKeywordActions]),
);
}),
flatMap(action => action),
catchError(error => of(actions.setError(error.message))),
);
但是我不喜欢从外部作用域获取addKeywordActions,如果您发送的搜索请求很少,switchMap
会重置所有链接。保留关键字数据会很好