[React] Create a queue of Ajax requests with redux-observable and group the results.
With redux-observable, we have the power of RxJS at our disposal - this means tasks that would otherwise be complicated and imperative, become simple and declarative. In this lesson we’ll respond to an action by queuing up 2 separate Ajax requests that will execute sequentially. Then we’ll group the results from both into an array and produce a single action from our epic that will save the data into the redux store
// action export const FETCH_STORIES = 'FETCH_STORIES'; export const FETCH_STORIES_FULFILLED = 'FETCH_STORIES_FULFILLED'; export function fetchStoriesAction(count = 5) { return { type: FETCH_STORIES, payload: count } } export function fetchStoriesFulfilledAction(stories) { return { type: FETCH_STORIES_FULFILLED, payload: stories } }
// epics import {Observable} from 'rxjs'; import {combineEpics} from 'redux-observable'; import {FETCH_STORIES, fetchStoriesFulfilledAction} from "../actions/index"; const topStories = `https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty`; const url = (id) => `https://hacker-news.firebaseio.com/v0/item/${id}.json?print=pretty`; function fetchStoriesEpic(action$) { return action$.ofType(FETCH_STORIES) .switchMap(({payload}) => { return Observable.ajax.getJSON(topStories) // slice first 5 ids .map(ids => ids.slice(0, 5)) // convert ids -> urls .map(ids => ids.map(url)) // convert urls -> ajax .map(urls => urls.map(url => Observable.ajax.getJSON(url))) // execute 5 ajax requests .mergeMap(reqs => Observable.forkJoin(reqs)) // results -> store .map(stories => fetchStoriesFulfilledAction(stories)) }) } export const rootEpic = combineEpics(fetchStoriesEpic);
import {FETCH_STORIES, FETCH_STORIES_FULFILLED} from "../actions/index";
const initialState = {
stories: [],
loading: false,
};
export function storiesReducer(state = initialState, action) {
switch(action.type) {
case FETCH_STORIES:
return {
stories: [],
loading: true
};
case FETCH_STORIES_FULFILLED:
return {
stories: action.payload,
loading: false
};
default: return state;
}
}
export default storiesReducer;
// component import React from 'react'; import {connect} from "react-redux"; import {fetchStoriesAction} from "../actions/index"; export function Stories(props) { if (props.loading) { return ( <p>Please wait...</p> ) } return ( <div> <button type="button" onClick={props.loadStories}>Load top 5 stories</button> <StoryList stories={props.stories} /> </div> ) } function StoryList(props) { return ( <ul> {props.stories.map(story => <li key={story.id}> <a href={story.url}>{story.title}</a> </li> )} </ul> ); } function mapState(state) { return state; } function mapDispatch(dispatch) { return { loadStories: () => dispatch(fetchStoriesAction()) } } export default connect(mapState, mapDispatch)(Stories);

浙公网安备 33010602011771号